ISLR Problem
A
We create 100 \(X\) and \(\epsilon\) variables using rnorm.
X = rnorm(100)
eps = rnorm(100)
B
We select \(\beta_0 = 1\) \(\beta_1 = 2\), \(\beta_2 = -1.4\), \(\beta_3 = 0.6\).
beta0 = 1
beta1 = 2.5
beta2 = -3.4
beta3 = 0.9
Y = beta0 + beta1 * X + beta2 * X^2 + beta3 * X^3 + eps
C
We use regsubsets with exhaustive search.
data_df = data.frame(y = Y, x = X)
fn_regsubsets_plots <- function(fit_obj, elbow = NULL) {
regsubsets_summary <- summary(fit_obj)
g <-
data_frame(
predictors = 1:length(regsubsets_summary$cp)
, cp = regsubsets_summary$cp
, bic = regsubsets_summary$bic
, adjr2 = regsubsets_summary$adjr2
) %>%
gather(metric, value, -predictors) %>%
mutate(metric = factor(metric, levels = c("cp","bic","adjr2"))) %>%
ggplot(aes(x = predictors, y = value, colour = metric)) +
facet_grid(metric ~ ., scale = "free_y", switch = "y",
labeller = ggplot2::labeller(metric = c(cp = "Cp", bic = "BIC", adjr2 = "Adjusted R^2"))) +
geom_line() + geom_point() +
geom_label(data = data_frame(
predictors = c(which.min(regsubsets_summary$cp), which.min(regsubsets_summary$bic),
which.max(regsubsets_summary$adjr2))
, metric = factor(c("cp","bic","adjr2"), levels = c("cp","bic","adjr2"))
, value = c(min(regsubsets_summary$cp), min(regsubsets_summary$bic), max(regsubsets_summary$adjr2))
, label = paste0("Optimal\nd=", c(which.min(regsubsets_summary$cp), which.min(regsubsets_summary$bic),
which.max(regsubsets_summary$adjr2)))
, vjust = c(-.5, -.5, 1.25)
), aes(x = predictors, y = value, label = label, vjust = vjust), family = "DecimaMonoPro") +
theme_jrf() +
labs(title = paste0(stringr::str_to_title(regsubsets_summary$obj$method), " Search"),
x = "# of Predictors", y = NULL) +
scale_colour_manual(guide = FALSE, values = c(pal538['red'][[1]], pal538['green'][[1]], pal538['blue'][[1]]))
if (!is.null(elbow)) {
g <- g + geom_vline(xintercept = elbow, alpha = 0.5) +
geom_label(data = data_frame(x = elbow, y = 300, metric = factor(c("cp"), levels = c("cp","bic","adjr2")),
label = "Elbow with\n3 predictors"), aes(x=x,y=y,label=label), colour = "black", hjust = -.1,
family = "DecimaMonoPro")
}
print(g)
}
fit1 = regsubsets(y ~ poly(x, 10, raw = TRUE), data = data_df, nvmax = 10, method = 'exhaustive')
fit1_summary = summary(fit1)
# Find the model size for best cp, BIC and adjr2
data_frame(
Cp = which.min(fit1_summary$cp)
, BIC = which.min(fit1_summary$bic)
, `Adj R^2` = which.max(fit1_summary$adjr2)
) %>%
pander(caption = "Exhaustive Search: Optimal Information Criterion")
Exhaustive Search: Optimal Information Criterion
| 3 |
3 |
3 |
fn_regsubsets_plots(fit1)

Based on the table and plots above for Exhaustive Search, the best model is
\[Y = \beta_0 + \beta_{1}X^1 + \beta_{2}X^2 + \beta_{3}X^3\]
D
fit2 = regsubsets(y ~ poly(x, 10, raw = TRUE), data = data_df, nvmax = 10, method = 'backward')
fit2_summary = summary(fit2)
# Find the model size for best cp, BIC and adjr2
data_frame(
Cp = which.min(fit2_summary$cp)
, BIC = which.min(fit2_summary$bic)
, `Adj R^2` = which.max(fit2_summary$adjr2)
) %>%
pander(caption = "Backwards Search: Optimal Information Criterion")
Backwards Search: Optimal Information Criterion
| 3 |
3 |
3 |
fn_regsubsets_plots(fit2)

Based on the table and plots above for Backwards Search, the best model is
\[Y = \beta_0 + \beta_{1}X^1 + \beta_{2}X^2 + \beta_{3}X^3\]
fit3 = regsubsets(y ~ poly(x, 10, raw = TRUE), data = data_df, nvmax = 10, method = 'forward')
fit3_summary = summary(fit3)
# Find the model size for best cp, BIC and adjr2
data_frame(
Cp = which.min(fit3_summary$cp)
, BIC = which.min(fit3_summary$bic)
, `Adj R^2` = which.max(fit3_summary$adjr2)
) %>%
pander(caption = "Forward Search: Optimal Information Criterion")
Forward Search: Optimal Information Criterion
| 3 |
3 |
3 |
fn_regsubsets_plots(fit3)

Based on the table and plots above for Forwards Search, the best model is
\[Y = \beta_0 + \beta_{1}X^1 + \beta_{2}X^2 + \beta_{3}X^3\]
We see that for the \(\beta\)s chosen, backwards and forwards search produces the same optimal model.
E
xmat = model.matrix(y ~ poly(x, 10, raw = T), data = data_df)[, -1]
mod.lasso = cv.glmnet(xmat, Y, alpha = 1)
best.lambda = mod.lasso$lambda.min
The optimal value of \(\lambda\) is 0.0681.
fn_plot_cv_glmnet <- function(cv_glmnet, main) {
data <-
tidy(cv_glmnet) %>% as_tibble() %>%
mutate(log_lambda = log(lambda))
data2 <-
data %>%
filter(row_number() %% 4 == 0)
data3 <-
data_frame(
log_lambda = c(log(cv_glmnet$lambda.min), log(cv_glmnet$lambda.1se))
, name = c("Min", "1se")
)
ggplot() +
geom_errorbar(data = data, aes(x = log_lambda, ymin = conf.low, ymax = conf.high),
colour = pal538['dkgray'][[1]], alpha = 0.6) +
geom_point(data = data, aes(x = log_lambda, y = estimate), colour = pal538['red'][[1]]) +
geom_vline(xintercept = log(cv_glmnet$lambda.min), colour = pal538['dkgray'][[1]], alpha = 0.6) +
geom_vline(xintercept = log(cv_glmnet$lambda.1se), colour = pal538['dkgray'][[1]], alpha = 0.6) +
theme_jrf() +
labs(title = main, x = expression(log(lambda)), y = cv_glmnet$name) +
geom_text(data = data2, aes(x = log_lambda, y = Inf, label = nzero), vjust = 1, colour = '#3C3C3C',
family = ifelse(Sys.info()[['user']] %in% users_v,"DecimaMonoPro", "Helvetica"),
size = 2.25) +
geom_label(data = data3, aes(x = log_lambda, y = Inf, label = name), vjust = 5, colour = '#3C3C3C',
family = ifelse(Sys.info()[['user']] %in% users_v,"DecimaMonoPro", "Helvetica"))
}
fn_plot_cv_glmnet(mod.lasso, "Lasso Model on Simulated Data")

best.model <- glmnet(xmat, Y, alpha = 1)
coeffiecients <- predict(best.model, s = best.lambda, type = "coefficients")
coeffiecients_df <-
data_frame(
coeffiecient = names(coeffiecients[, 1])
, estimate = coeffiecients[, 1]
) %>%
mutate(estimate = ifelse(estimate == 0, NA, estimate)) %>%
mutate(coeffiecient = paste0("$\\beta_{", row_number() - 1, "}$"))
betas_above_3 <-
coeffiecients_df %>%
filter(is.na(estimate) & row_number() > 4) %>%
select(coeffiecient) %>%
unlist() %>%
stringr::str_extract("(\\d+)")
coeffiecients_df %>%
pander(missing = "")
| \(\beta_{0}\) |
9.993e-01 |
| \(\beta_{1}\) |
2.329e+00 |
| \(\beta_{2}\) |
-3.458e+00 |
| \(\beta_{3}\) |
9.076e-01 |
| \(\beta_{4}\) |
-8.271e-04 |
| \(\beta_{5}\) |
6.297e-06 |
| \(\beta_{6}\) |
|
| \(\beta_{7}\) |
6.832e-05 |
| \(\beta_{8}\) |
|
| \(\beta_{9}\) |
5.934e-06 |
| \(\beta_{10}\) |
|
Lasso picks \(X_{3}\),\(X_{4}\),\(X_{5}\),\(X_{6}\),\(X_{7}\),\(X_{8}\),\(X_{9}\),\(X_{10}\) over \(X_3\).
F
We select \(\beta_7 = 7\) and regsubsets with Exhaustive Search.
beta7 = 7
Y2 = beta0 + beta7 * X^7 + eps
data_df2 <- data_frame(y = Y2, x = X)
fit7 = regsubsets(y ~ poly(x, 10, raw = TRUE), data = data_df2, nvmax = 10, method = 'exhaustive')
fn_regsubsets_plots(fit7)

For a model with one predictor, the estimates is very close to the actual coefficients:
\[Y = 0.9428 + 7.0002X^7\]
Now using lasso,
xmat2 = model.matrix(y ~ poly(x, 10, raw = T), data = data_df2)[, -1]
mod.lasso2 = cv.glmnet(xmat2, Y2, alpha = 1)
best.lambda2 = mod.lasso2$lambda.min
fn_plot_cv_glmnet(mod.lasso2, "Lasso Model on Simulated Data")

best.model2 = glmnet(xmat2, Y, alpha = 1)
coeffiecients2 = predict(best.model2, s = best.lambda2, type = "coefficients")
coeffiecients_df2 <-
data_frame(
coeffiecient = names(coeffiecients2[, 1])
, estimate = coeffiecients2[, 1]
) %>%
mutate(estimate = ifelse(estimate == 0, NA, estimate)) %>%
mutate(coeffiecient = paste0("$\\beta_{", row_number() - 1, "}$"))
betas_above_3 <- coeffiecients_df2 %>% filter(is.na(estimate) & row_number() > 3) %>% select(coeffiecient) %>% unlist() %>% stringr::str_extract("(\\d+)")
coeffiecients_df2 %>%
pander(missing = "")
| \(\beta_{0}\) |
-4.307 |
| \(\beta_{1}\) |
|
| \(\beta_{2}\) |
|
| \(\beta_{3}\) |
|
| \(\beta_{4}\) |
|
| \(\beta_{5}\) |
|
| \(\beta_{6}\) |
|
| \(\beta_{7}\) |
|
| \(\beta_{8}\) |
|
| \(\beta_{9}\) |
|
| \(\beta_{10}\) |
|
Lasso only selects the intercept term and not \(X^7\) and the intercept is quite off.
Crime Data
Part 1
The map below shows the mean of the pct.unemployed variable in CrimeData.csv. This metric does not make much sense because it the average of a percent of a subset of communities in the US. This is to demonstrate the functionality.
crime_data <- readr::read_csv(paste0(data_dir, "CrimeData.csv"), na = c("","?"))
data("state")
data("usgeojson")
df <-
data_frame(State = rownames(state.x77), abb = state.abb) %>%
inner_join(
crime_data %>%
group_by(state) %>%
summarise(mean_pct.unemployed = mean(pct.unemployed))
, by = c("abb" = "state")
)
highchart() %>%
hc_title(text = "Mean of Percentage of Unemployed") %>%
hc_subtitle(text = "Source: CrimeData.csv") %>%
hc_add_series_map(usgeojson, df, name = "Per Capita Income (1974)",
value = "mean_pct.unemployed", joinBy = c("woename", "State"),
dataLabels = list(enabled = TRUE,
format = '{point.properties.postalcode}')) %>%
hc_colorAxis(min = min(df$Income)) %>%
hc_legend(valueDecimals = 0, valueSuffix = "%") %>%
hc_tooltip(valuePrefix = "%", valueDecimals = 1) %>%
hc_mapNavigation(enabled = TRUE) %>%
hc_credits(enabled = TRUE, text = "Inspired by http://jkunst.com/highcharter/highmaps.html",
href = "http://jkunst.com/highcharter/highmaps.html")
The map below shows the population by county from the CrimeData.csv dataset. There are many communities in the dataset that are missing county codes and many counties are missing all the communities. Again, this is to demonstrate the functionality.
data("uscountygeojson")
crime_data2 <-
crime_data %>%
filter(county != "?") %>%
group_by(state, county) %>%
summarise(population = sum(population)) %>%
mutate(code = paste0('us-',tolower(state),'-', stringr::str_pad(county, 3, side = "left", pad = "0"))) %>%
select(state, county, code, population)
n <- 16
dstops <- data.frame(q = 0:n/n, c = rev(substring(viridis(n + 1, option = "B"), 0, 7)))
dstops <- list_parse2(dstops)
highchart() %>%
hc_title(text = "Population by County") %>%
hc_subtitle(text = "Source: CrimeData.csv") %>%
hc_add_series_map(map = uscountygeojson, df = crime_data2,
value = "population", joinBy = c("code", "code"),
name = "Population", borderWidth = 0.1) %>%
hc_colorAxis(stops = dstops, min = min(crime_data2$population)) %>%
hc_legend(layout = "vertical", reversed = TRUE,
floating = TRUE, align = "right") %>%
hc_mapNavigation(enabled = TRUE, align = "right") %>%
hc_tooltip(valueDecimals = 0) %>%
hc_credits(enabled = TRUE, text = "Inspired by http://jkunst.com/highcharter/highmaps.html",
href = "http://jkunst.com/highcharter/highmaps.html")
Part 2
var_names_out <- c("num.urban","other.percap","num.underpov","num.vacant.house","num.murders","num.rapes",
"num.robberies","num.assaults","num.burglaries","num.larcenies","num.autothefts","num.arsons")
names_other_crimes <- c("murder.perpop", "rapes.perpop","robberies.perpop","assaults.perpop","nonviolentcrimes.perpop",
"burglaries.perpop","larcenies.perpop","autothefts.perpop","arsons.perpop")
data_cafl <-
crime_data %>%
select(c(2,6:103,121,122,123, 130:147)) %>%
select(-one_of(c(var_names_out, names_other_crimes))) %>%
filter(state %in% c("FL","CA")) %>%
filter(complete.cases(.))
From the CrimeData.csv dataset we extract the data for only the states CA and FL. In addition, we select only variables from following the process used in Lecture 6 and remove missing values. As a result we have 368 observation and 99 variables.
(A)
We perform 10-fold cross-validation for glmnet with \(\alpha\) = 0.99.
x_matrix_flca <- model.matrix(violentcrimes.perpop ~ ., data = data_cafl)[, -1]
y_violent_crimes <-
data_cafl %>%
select(violentcrimes.perpop) %>%
unlist()
fit_cafl_1 <- cv.glmnet(x_matrix_flca, y_violent_crimes, alpha = .99, nfolds = 10)
fn_plot_cv_glmnet(fit_cafl_1, expression("FL & CA Crime Data: ElasticNet "~ alpha ~"= 0.99"))

We see that the mean cross-validated error is minimized when \(\lambda = e^{4.2907} = 73.0182\) and there are 5 non-zero estimates of \(\beta_i\). We will use this with glmnet to create new fit.
fit_cafl_2 <- glmnet(x_matrix_flca, y_violent_crimes, alpha = .99, lambda = fit_cafl_1$lambda.min)
relevent_vars <-
tidy(fit_cafl_2) %>%
filter(estimate != 0 & term != "(Intercept)")
regsubsets_cafl1 <-
regsubsets(as.formula(paste0("violentcrimes.perpop ~ ", paste0(relevent_vars$term, collapse = " + "))),
nvmax = 15, method = "exhaustive", data = data_cafl)
summary(regsubsets_cafl1)$outmat %>%
as_tibble() %>%
pander(missing = "", split.table = Inf)
|
|
* |
|
|
|
* |
* |
|
|
| * |
* |
* |
|
|
| * |
* |
* |
|
* |
| * |
* |
* |
* |
* |
The table above shows which of the five varaibles would be present in the optimal model at each # of predictors. For example, note that pct.house.vacant would not be present if only 4 variables were used. We create a plot to show the optimal # of predictors based on Cp, BIC, and Adjusted \(R^2\).
fn_regsubsets_plots(regsubsets_cafl1)

The optimal model based ont the BIC criteria uses 4 predictors, but based on Cp the optimal model would include 5 predictors. We will only create a model if the \(p\)-values are less than 0.05. We’ll create this model and note that all variables are significant at the 0.05 level. However, the variable pct.house.vacant is just barely significant.
fit_cafl_3 <- lm(as.formula(paste0("violentcrimes.perpop ~ ",
paste0(summary(regsubsets_cafl1)$obj$xnames[-1], collapse = " + "))), data = data_cafl)
tidy(fit_cafl_3) %>% arrange(p.value) %>% pander()
| (Intercept) |
1991 |
261.6 |
7.609 |
2.411e-13 |
| pct.kids2parents |
-22.52 |
3.312 |
-6.8 |
4.331e-11 |
| pct.kids.nvrmarried |
81.55 |
12.68 |
6.43 |
4.023e-10 |
| race.pctblack |
13.5 |
2.718 |
4.967 |
1.05e-06 |
| num.in.shelters |
0.1587 |
0.05364 |
2.958 |
0.003299 |
| pct.house.vacant |
24.77 |
10.97 |
2.259 |
0.02449 |
We remove pct.house.vacant, fit another linear model, and see all the variables are signifcant at a 0.01 confidence level.
cafl_terms <-
tidy(fit_cafl_3) %>%
filter(term != "(Intercept)") %>%
arrange(p.value) %>%
select(term) %>%
unlist()
fit_cafl_4 <- lm(as.formula(paste0("violentcrimes.perpop ~ ", paste0(cafl_terms[-5], collapse = " + "))), data = data_cafl)
tidy_cafl_1 <- tidy(fit_cafl_4) %>% arrange(p.value)
tidy_cafl_1 %>% pander()
| (Intercept) |
2002 |
263.1 |
7.611 |
2.366e-13 |
| pct.kids.nvrmarried |
89.63 |
12.24 |
7.325 |
1.555e-12 |
| pct.kids2parents |
-22.5 |
3.33 |
-6.756 |
5.647e-11 |
| race.pctblack |
14.27 |
2.711 |
5.265 |
2.41e-07 |
| num.in.shelters |
0.1698 |
0.05371 |
3.162 |
0.001702 |
Though the requirements of the problem state to include variables with \(p\)-values less than 0.05, in order to create a parsimonious linear model we will exclude the variable pct.house.vacant as this does provide much more explanatory power. The BIC criteria, which has a much harsher complexity penalty than Cp, indicates 4 variables is optimal and we will follow this heuristic. Moreover, we believe in the maxim that simpler models are always better.
The final model is
\[violentcrimes.perpop = 2002.3118 +
89.633pct.kids.nvrmarried +
-22.5007pct.kids2parents +
14.2725race.pctblack + \\
0.1698num.in.shelters\]
Holding all other variables constant in a community,
- An increase in 1% of families with kids and 2 parents, decreases the number of violent crimes per person by 89.633.
- An increase in 1% of families with kids with unmarried parents, increases the number of violent crimes per person by -22.5007.
- An increase in 1% of black residents, increases the number of violent crimes per person by 14.2725.
- An increase in 1% of the number of shelters, increases the number of violent crimes per person by 0.1698.
(B)
In order to cross-validate lambdas and alphas, we use the caret package which generalizes model training and testing. Two important inputs to the train function are a trainControl and tuneGrid. In the trainControl we specify 10-fold cross-validation, repeated 5 times. As both lambdas and alphas are statistics it is important to use repeated cross-validation in this scenario. In the tuneGrid we specify which alphas and lambdas to attempt. For alphas, we use a sequence between 0 and 1 and for lambdas we use the original lambdas found in part (A).
We then plot the alpha and lambda combinations against the mean-squared error (MSE) and highlight the combination that minimizes the MSE.
glmnetTrControl <-
trainControl(
method = "repeatedCV"
, number = 10
, repeats = 5
)
glmnetGrid <-
expand.grid(
alpha = seq(0, 1, 0.1)
, lambda = fit_cafl_1$lambda
)
set.seed(42)
model <-
train(
violentcrimes.perpop ~ .
, data = data_cafl
, method = 'glmnet'
, tuneGrid = glmnetGrid
, trControl = glmnetTrControl
)
model_results <-
model$results %>%
as_tibble() %>%
mutate(
log_lambda = log(lambda)
, alpha = round(alpha, 1)
, MSE = RMSE^2
)
minimized <- model_results %>% arrange(RMSE) %>% filter(row_number() == 1)
data_cafl2 <-
data_cafl %>%
select(one_of(c("violentcrimes.perpop"), predictors(model)))
x_matrix_flca2 <- model.matrix(violentcrimes.perpop ~ ., data = data_cafl2)[, -1]
glmnet_fit1 <- glmnet(x_matrix_flca2, y_violent_crimes, alpha = model$bestTune$alpha, lambda = model$bestTune$lambda)
tidy_cafl_2 <- tidy(glmnet_fit1)
ggplot() +
theme_jrf() +
geom_line(data = model_results, aes(x = log_lambda, y = MSE,
group = as.factor(alpha), colour = as.factor(alpha))) +
geom_point(aes(x = minimized$log_lambda, y = minimized$MSE), colour = pal538['dkgray'][[1]]) +
labs(title = "Cross Validation of Alpha and Lambda", x = expression(log(lambda)),
y = "Mean-Squared Error (Repeated Cross-Validation)") +
scale_colour_discrete(guide = guide_legend(title = expression(alpha))) +
geom_segment(aes(x = minimized$log_lambda, xend = minimized$log_lambda, y = 500^2, yend = 390^2),
arrow = arrow(length = unit(0.03, "npc")), colour = pal538['dkgray'][[1]], alpha = 0.5) +
geom_label(data = data_frame(x = minimized$log_lambda, y = 500^2, label = "Alpha and Lambda\nthat Minimize MSE"),
aes(x = x, y = y, label = label), colour = pal538['dkgray'][[1]], family = "DecimaMonoPro")

This model uses 15 predictors: race.pctblack, pct.farmself.inc, pct.inv.inc, asian.percap, male.pct.divorce, pct.kids2parents, pct.workmom, num.kids.nvrmarried, pct.kids.nvrmarried, pct.english.only, pct.house.occup, pct.house.vacant, med.yr.house.built, pct.house.nophone and num.in.shelters. The optimal parameters are
\[\alpha = 1\] \[\lambda = 26.2414\]
and the equation is
\[violentcrimes.perpop = 4958.2725 +
16.836race.pctblack +
-15.8618pct.farmself.inc +
-0.8978pct.inv.inc + \\
0.0026asian.percap +
23.5108male.pct.divorce +
-16.8671pct.kids2parents + \\
-4.8738pct.workmom +
8.9613\times 10^{-4}num.kids.nvrmarried +
58.8977pct.kids.nvrmarried + \\
-3.0611pct.english.only +
-1.7794pct.house.occup +
11.4984pct.house.vacant + \\
-1.4255med.yr.house.built +
7.1541pct.house.nophone +
0.0849num.in.shelters\]
The prediction error of this model is 149,055.
We then use these predictors in OLS and find the prediction error is 152,690.
fit_cafl_6 <- lm(as.formula(paste0("violentcrimes.perpop ~ ", paste0(predictors(model), collapse = " + "))),
data = data_cafl)
tidy_cafl_3 <-
tidy(fit_cafl_6) %>%
mutate(isIntercept = ifelse(term == "(Intercept)", 0, 1)) %>%
arrange(isIntercept, p.value) %>%
select(-isIntercept)
tidy_cafl_3 %>% pander()
| (Intercept) |
11813 |
6352 |
1.86 |
0.06376 |
| race.pctblack |
22.29 |
3.428 |
6.501 |
2.732e-10 |
| male.pct.divorce |
38.96 |
11.93 |
3.264 |
0.001204 |
| asian.percap |
0.007932 |
0.00253 |
3.136 |
0.001858 |
| pct.kids2parents |
-13.03 |
4.769 |
-2.733 |
0.006598 |
| pct.english.only |
-5.699 |
2.158 |
-2.641 |
0.008647 |
| pct.workmom |
-8.398 |
3.696 |
-2.272 |
0.02367 |
| pct.house.occup |
-7.865 |
3.979 |
-1.977 |
0.04886 |
| pct.kids.nvrmarried |
33.74 |
17.98 |
1.876 |
0.06146 |
| num.in.shelters |
0.1339 |
0.08088 |
1.655 |
0.09878 |
| pct.inv.inc |
-4.781 |
3.16 |
-1.513 |
0.1312 |
| med.yr.house.built |
-4.546 |
3.187 |
-1.427 |
0.1546 |
| pct.farmself.inc |
-60.13 |
43.85 |
-1.371 |
0.1712 |
| pct.house.vacant |
12.38 |
10.94 |
1.131 |
0.2588 |
| pct.house.nophone |
11.41 |
10.88 |
1.049 |
0.2949 |
| num.kids.nvrmarried |
0.001592 |
0.002584 |
0.6161 |
0.5383 |
We see there are now predicators that are not significant at the 0.05 significance level.
\[violentcrimes.perpop = 1.1813\times 10^{4} +
22.2876race.pctblack +
38.961male.pct.divorce +
0.0079asian.percap + \\
-13.0321pct.kids2parents +
-5.6991pct.english.only +
-8.398pct.workmom + \\
-7.8647pct.house.occup +
33.7405pct.kids.nvrmarried +
0.1339num.in.shelters + \\
-4.7811pct.inv.inc +
-4.5459med.yr.house.built +
-60.1253pct.farmself.inc + \\
12.3785pct.house.vacant +
11.4147pct.house.nophone +
0.0016num.kids.nvrmarried\]
For example, holding all other variables constant in a community,
- An increase in 1% of black residents, increases the number of violent crimes per person by 22.2876.
- An increase in 1% of males that that are divorced, increases the number of violent crimes per person by 38.961.
- An increase in 1% of Asian residences, increases the number of violent crimes per person by 38.961.
- An increase in 1% of families with kids and 2 parents, decreases the number of violent crimes per person by 0.0079.
- An increase in 1% of English only speakers, decreases the number of violent crimes per person by -13.0321.
- An increase in 1% of working mothers, decreases the number of violent crimes per person by -5.6991.
- An increase in 1% of occupied houses, decreases the number of violent crimes per person by -8.398.
This is only the first seven variables, but such statements could be applied to all predictors.
The equation from ElasticNet and OLS are similar in the respect that they contain the same predictors (this is by design), but the coefficient estimates are slightly different.
LS0tCnRpdGxlOiAiU1RBVFM3MDEgSG9tZXdvcmsgMyIKYXV0aG9yOiAiSm9yZGFuIEZhcnJlciIKZGF0ZTogJzIwMTYtMTAtMzAnCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjc3M6IHN0eWxlLmNzcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBmbGF0bHkKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwotLS0KCgpGdWxsIHJlcG86IFtodHRwczovL2dpdGh1Yi5jb20vanJmYXJyZXIvc3RhdHM3MDFfaHczL10oaHR0cHM6Ly9naXRodWIuY29tL2pyZmFycmVyL3N0YXRzNzAxX2h3My8pCgpQdWJsaXNoZWQgZmlsZTogW2h0dHBzOi8vanJmYXJyZXIuZ2l0aHViLmlvL3N0YXRzNzAxX2h3My9dKGh0dHBzOi8vanJmYXJyZXIuZ2l0aHViLmlvL3N0YXRzNzAxX2h3My8pCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgU2V0IG9wdGlvbnMgZm9yIHRoZSBybWFya2Rvd24gZmlsZQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBmaWcuYWxpZ24gPSAnY2VudGVyJywgd2lkdGggPSAxMDApCmBgYAoKYGBge3Igc2V0dXAyfQojIFNldCB0aGUgc2VlZCBmb3IgcmVwcm9kdWNpYmlsaXR5CnNldC5zZWVkKDQ0KQojIFNldCB0aGUgbG9jYWxlIG9mIHRoZSBzZXNzaW9uIHNvIGxhbmd1YWdlcyBvdGhlciB0aGFuIEVuZ2xpc2ggY2FuIGJlIHVzZWQKaW52aXNpYmxlKFN5cy5zZXRsb2NhbGUoIkxDX0FMTCIsICJlbl9VUy5VVEYtOCIpKQojIFByZXZlbnQgcHJpbnRpbmcgaW4gc2NpZW50aWZpYyBub3RhdGlvbgpvcHRpb25zKGRpZ2l0cyA9IDQsIHdpZHRoID0gMjIwKQoKIyBDcmVhdGUgYSBsb2dnZXIgZnVuY3Rpb24KbG9nZ2VyIDwtIGZ1bmN0aW9uKG1zZywgbGV2ZWwgPSAiaW5mbyIsIGZpbGUgPSBsb2dfZmlsZSkgewogICAgY2F0KHBhc3RlMCgiWyIsIGZvcm1hdChTeXMudGltZSgpLCAiJVktJW0tJWQgJUg6JU06JVMuJU9TIiksICJdWyIsIGxldmVsLCAiXSAiLCBtc2csICJcbiIpLCBmaWxlID0gc3Rkb3V0KCkpCn0KCiMgU2V0IHRoZSBwcm9qZWN0IGRpcmVjdG9yeQpiYXNlX2RpciA8LSAnJwpkYXRhX2RpciA8LSBwYXN0ZTAoYmFzZV9kaXIsICJkYXRhLyIpCmNvZGVfZGlyIDwtIHBhc3RlMChiYXNlX2RpciwgImNvZGUvIikKdml6X2RpciA8LSBwYXN0ZTAoYmFzZV9kaXIsICJ2aXovIikKCmRpci5jcmVhdGUoZGF0YV9kaXIsIHNob3dXYXJuaW5ncyA9IEZBTFNFKQpkaXIuY3JlYXRlKGNvZGVfZGlyLCBzaG93V2FybmluZ3MgPSBGQUxTRSkKZGlyLmNyZWF0ZSh2aXpfZGlyLCBzaG93V2FybmluZ3MgPSBGQUxTRSkKYGBgCgpgYGB7ciBMb2FkIFBhY2thZ2VzLCBpbmNsdWRlID0gRkFMU0V9CiMgQ3JlYXRlIGEgZnVuY3Rpb24gdGhhdCB3aWxsIGJlIHVzZWQgdG8gbG9hZC9pbnN0YWxsIHBhY2thZ2VzCmZuX2xvYWRfcGFja2FnZXMgPC0gZnVuY3Rpb24ocCkgewogIGlmICghaXMuZWxlbWVudChwLCBpbnN0YWxsZWQucGFja2FnZXMoKVssMV0pIHx8IChwID09IkRUIiAmJiAhKHBhY2thZ2VWZXJzaW9uKHApID4gIjAuMSIpKSkgewogICAgaWYgKHAgPT0gIkRUIikgewogICAgICBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoJ3JzdHVkaW8vRFQnKQogICAgfSBlbHNlIHsKICAgICAgaW5zdGFsbC5wYWNrYWdlcyhwLCBkZXAgPSBUUlVFLCByZXBvcyA9ICdodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnJykKICAgIH0KICB9CiAgYSA8LSBzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMocmVxdWlyZShwLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKQogIGlmIChhKSB7CiAgICBsb2dnZXIocGFzdGUwKCJMb2FkZWQgcGFja2FnZSAiLCBwLCAiIHZlcnNpb24gIiwgcGFja2FnZVZlcnNpb24ocCkpKQogIH0gZWxzZSB7CiAgICBsb2dnZXIocGFzdGUwKCJVbmFibGUgdG8gbG9hZCBwYWNrYWdlcyAiLCBwKSkKICB9Cn0KIyBDcmVhdGUgYSB2ZWN0b3Igb2YgcGFja2FnZXMKcGFja2FnZXMgPC0gYygndGlkeXZlcnNlJywnZ2d0aGVtZXMnLCdrbml0cicsJ2V4dHJhZm9udCcsJ2Jyb29tJywnYW9kJywnbGVhcHMnLCdiZXN0Z2xtJywnZ2xtbmV0JywKICAgICAgICAgICAgICAnR0dhbGx5JywncGFuZGVyJywnZGVzY3InLCdwbG90Uk9DJywgJ1JPQ1InLCdwUk9DJywgJ2NvcnJwbG90JywnY2FyZXQnLAogICAgICAgICAgICAgICdoaWdoY2hhcnRlcicsJ3ZpcmlkaXNMaXRlJywnc3RyaW5ncicsJ3JlYWRyJykKIyBVc2UgZnVuY3Rpb24gdG8gbG9hZCB0aGUgcmVxdWlyZWQgcGFja2FnZXMKaW52aXNpYmxlKGxhcHBseShwYWNrYWdlcywgZm5fbG9hZF9wYWNrYWdlcykpCmBgYAoKYGBge3IgSW1wb3J0IEZvbnRzfQojIFRvIHRoZSBmb250IHNlY29uZCBmb250LCBydW4gdGhlIGZvbGxvd2luZyB0d28gbGluZXMgb2YgY29kZSBhbmQgYWRkIG5hbWUgb2YgdXNlciB0byB2ZWN0b3IKIyBzeXN0ZW0ocGFzdGUwKCJjcCAtciAiLHZpel9kaXIsImZvbnRzLy4gfi9MaWJyYXJ5L0ZvbnRzLyIpKSAjIGluc3RhbnRhbmVvdXMKIyBmb250X2ltcG9ydCgpICMgdGFrZXMgYXBwcm94aW1hdGVseSA1LTEwIG1pbgp1c2Vyc192IDwtIGMoIkpvcmRhbiIpCmBgYAoKYGBge3IgQ3JlYXRlIHBhbGV0dGUgYW5kIHRoZW1lfQojIENyZWF0ZSBhIGNvbG9yIHBhbGV0dGUKcGFsNTM4IDwtIGdndGhlbWVzX2RhdGEkZml2ZXRoaXJ0eWVpZ2h0CgojIENyZWF0ZSBhIHRoZW1lIHRvIHVzZSB0aHJvdWdob3V0IHRoZSBhbmFseXNpcwp0aGVtZV9qcmYgPC0gZnVuY3Rpb24oYmFzZV9zaXplID0gOCwgYmFzZV9mYW1pbHkgPSBpZmVsc2UoU3lzLmluZm8oKVtbJ3VzZXInXV0gJWluJSB1c2Vyc192LCAiRGVjaW1hTW9ub1BybyIsICJIZWx2ZXRpY2EiKSkgewogICAgdGhlbWUoCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0YwRjBGMCIsIGNvbG91ciA9ICIjNjA2MDYzIiksIAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRjBGMEYwIiwgY29sb3VyID0gTkEpLCAKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9ICAgZWxlbWVudF9saW5lKGNvbG91ciA9ICIjRDdEN0Q4IiksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9ICAgZWxlbWVudF9saW5lKGNvbG91ciA9ICIjRDdEN0Q4Iiwgc2l6ZSA9IDAuMjUpLAogICAgICAgIHBhbmVsLm1hcmdpbiA9ICAgICAgIHVuaXQoMC4yNSwgImxpbmVzIiksCiAgICAgICAgcGFuZWwubWFyZ2luLnggPSAgICAgTlVMTCwKICAgICAgICBwYW5lbC5tYXJnaW4ueSA9ICAgICBOVUxMLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3VyID0gIiNBMEEwQTMiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDEsIGNvbG91ciA9ICcjM0MzQzNDJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBpZmVsc2UoU3lzLmluZm8oKVtbJ3VzZXInXV0gJWluJSB1c2Vyc192LCJEZWNpbWFNb25vUHJvIiwgIkhlbHZldGljYSIpKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDEsIGNvbG91ciA9ICcjM0MzQzNDJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gaWZlbHNlKFN5cy5pbmZvKClbWyd1c2VyJ11dICVpbiUgdXNlcnNfdiwiRGVjaW1hTW9ub1BybyIsICJIZWx2ZXRpY2EiKSksCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gJ2JvbGQnLCBjb2xvdXIgPSAnIzNDM0MzQycsIGhqdXN0ID0gMCksCiAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgZmFtaWx5ID0gaWZlbHNlKFN5cy5pbmZvKClbWyd1c2VyJ11dICVpbiUgdXNlcnNfdiwiRGVjaW1hTW9ub1BybyIsICJIZWx2ZXRpY2EiKSksCiAgICAgICAgdGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gaWZlbHNlKFN5cy5pbmZvKClbWyd1c2VyJ11dICVpbiUgdXNlcnNfdiwiRGVjaW1hTW9ub1BybyIsICJIZWx2ZXRpY2EiKSkKICAgICAgICAKICAgICkKfQpgYGAKCiMgSVNMUiBQcm9ibGVtCgojIyBBCgpXZSBjcmVhdGUgMTAwICRYJCBhbmQgJFxlcHNpbG9uJCB2YXJpYWJsZXMgdXNpbmcgYHJub3JtYC4KCmBgYHtyfQpYID0gcm5vcm0oMTAwKQplcHMgPSBybm9ybSgxMDApCmBgYAoKIyMgQgoKV2Ugc2VsZWN0ICRcYmV0YV8wID0gMSQgJFxiZXRhXzEgPSAyJCwgJFxiZXRhXzIgPSAtMS40JCwgJFxiZXRhXzMgPSAwLjYkLgoKYGBge3J9CmJldGEwID0gMQpiZXRhMSA9IDIuNQpiZXRhMiA9IC0zLjQKYmV0YTMgPSAwLjkKWSA9IGJldGEwICsgYmV0YTEgKiBYICsgYmV0YTIgKiBYXjIgKyBiZXRhMyAqIFheMyArIGVwcwpgYGAKCgojIyBDCgpXZSB1c2UgYHJlZ3N1YnNldHNgIHdpdGggZXhoYXVzdGl2ZSBzZWFyY2guCgpgYGB7cn0KZGF0YV9kZiA9IGRhdGEuZnJhbWUoeSA9IFksIHggPSBYKQpgYGAKCmBgYHtyfQpmbl9yZWdzdWJzZXRzX3Bsb3RzIDwtIGZ1bmN0aW9uKGZpdF9vYmosIGVsYm93ID0gTlVMTCkgewoKICAgIHJlZ3N1YnNldHNfc3VtbWFyeSA8LSBzdW1tYXJ5KGZpdF9vYmopCiAgICAKICAgIGcgPC0gCiAgICBkYXRhX2ZyYW1lKAogICAgICAgICAgcHJlZGljdG9ycyA9IDE6bGVuZ3RoKHJlZ3N1YnNldHNfc3VtbWFyeSRjcCkKICAgICAgICAsIGNwID0gcmVnc3Vic2V0c19zdW1tYXJ5JGNwCiAgICAgICAgLCBiaWMgPSByZWdzdWJzZXRzX3N1bW1hcnkkYmljCiAgICAgICAgLCBhZGpyMiA9IHJlZ3N1YnNldHNfc3VtbWFyeSRhZGpyMgogICAgKSAlPiUKICAgICAgICBnYXRoZXIobWV0cmljLCB2YWx1ZSwgLXByZWRpY3RvcnMpICU+JQogICAgICAgIG11dGF0ZShtZXRyaWMgPSBmYWN0b3IobWV0cmljLCBsZXZlbHMgPSBjKCJjcCIsImJpYyIsImFkanIyIikpKSAlPiUKICAgICAgICBnZ3Bsb3QoYWVzKHggPSBwcmVkaWN0b3JzLCB5ID0gdmFsdWUsIGNvbG91ciA9IG1ldHJpYykpICsKICAgICAgICBmYWNldF9ncmlkKG1ldHJpYyB+IC4sIHNjYWxlID0gImZyZWVfeSIsIHN3aXRjaCA9ICJ5IiwgCiAgICAgICAgICAgICAgICAgICBsYWJlbGxlciA9IGdncGxvdDI6OmxhYmVsbGVyKG1ldHJpYyA9IGMoY3AgPSAiQ3AiLCBiaWMgPSAiQklDIiwgYWRqcjIgPSAiQWRqdXN0ZWQgUl4yIikpKSArCiAgICAgICAgZ2VvbV9saW5lKCkgKyBnZW9tX3BvaW50KCkgKwogICAgICAgIGdlb21fbGFiZWwoZGF0YSA9IGRhdGFfZnJhbWUoCiAgICAgICAgICAgIHByZWRpY3RvcnMgPSBjKHdoaWNoLm1pbihyZWdzdWJzZXRzX3N1bW1hcnkkY3ApLCB3aGljaC5taW4ocmVnc3Vic2V0c19zdW1tYXJ5JGJpYyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLm1heChyZWdzdWJzZXRzX3N1bW1hcnkkYWRqcjIpKQogICAgICAgICAgICAsIG1ldHJpYyA9IGZhY3RvcihjKCJjcCIsImJpYyIsImFkanIyIiksIGxldmVscyA9IGMoImNwIiwiYmljIiwiYWRqcjIiKSkKICAgICAgICAgICAgLCB2YWx1ZSA9IGMobWluKHJlZ3N1YnNldHNfc3VtbWFyeSRjcCksIG1pbihyZWdzdWJzZXRzX3N1bW1hcnkkYmljKSwgbWF4KHJlZ3N1YnNldHNfc3VtbWFyeSRhZGpyMikpCiAgICAgICAgICAgICwgbGFiZWwgPSBwYXN0ZTAoIk9wdGltYWxcbmQ9IiwgYyh3aGljaC5taW4ocmVnc3Vic2V0c19zdW1tYXJ5JGNwKSwgd2hpY2gubWluKHJlZ3N1YnNldHNfc3VtbWFyeSRiaWMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2gubWF4KHJlZ3N1YnNldHNfc3VtbWFyeSRhZGpyMikpKQogICAgICAgICAgICAsIHZqdXN0ID0gYygtLjUsIC0uNSwgMS4yNSkKICAgICAgICApLCBhZXMoeCA9IHByZWRpY3RvcnMsIHkgPSB2YWx1ZSwgbGFiZWwgPSBsYWJlbCwgdmp1c3QgPSB2anVzdCksIGZhbWlseSA9ICJEZWNpbWFNb25vUHJvIikgKwogICAgICAgIHRoZW1lX2pyZigpICsgCiAgICAgICAgbGFicyh0aXRsZSA9IHBhc3RlMChzdHJpbmdyOjpzdHJfdG9fdGl0bGUocmVnc3Vic2V0c19zdW1tYXJ5JG9iaiRtZXRob2QpLCAiIFNlYXJjaCIpLCAKICAgICAgICAgICAgIHggPSAiIyBvZiBQcmVkaWN0b3JzIiwgeSA9IE5VTEwpICsKICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKGd1aWRlID0gRkFMU0UsIHZhbHVlcyA9IGMocGFsNTM4WydyZWQnXVtbMV1dLCBwYWw1MzhbJ2dyZWVuJ11bWzFdXSwgcGFsNTM4WydibHVlJ11bWzFdXSkpCiAgICAKICAgIGlmICghaXMubnVsbChlbGJvdykpIHsKICAgICAgICBnIDwtIGcgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBlbGJvdywgYWxwaGEgPSAwLjUpICsgCiAgICAgICAgICAgIGdlb21fbGFiZWwoZGF0YSA9IGRhdGFfZnJhbWUoeCA9IGVsYm93LCB5ID0gMzAwLCBtZXRyaWMgPSBmYWN0b3IoYygiY3AiKSwgbGV2ZWxzID0gYygiY3AiLCJiaWMiLCJhZGpyMiIpKSwgCiAgICAgICAgICAgICAgICBsYWJlbCA9ICJFbGJvdyB3aXRoXG4zIHByZWRpY3RvcnMiKSwgYWVzKHg9eCx5PXksbGFiZWw9bGFiZWwpLCBjb2xvdXIgPSAiYmxhY2siLCBoanVzdCA9IC0uMSwKICAgICAgICAgICAgICAgZmFtaWx5ID0gIkRlY2ltYU1vbm9Qcm8iKQogICAgfQogICAgCiAgICBwcmludChnKQp9CiAgICAgICAgCmBgYAoKYGBge3IgcmVzdWx0cyA9ICdhc2lzJ30KZml0MSA9IHJlZ3N1YnNldHMoeSB+IHBvbHkoeCwgMTAsIHJhdyA9IFRSVUUpLCBkYXRhID0gZGF0YV9kZiwgbnZtYXggPSAxMCwgbWV0aG9kID0gJ2V4aGF1c3RpdmUnKQpmaXQxX3N1bW1hcnkgPSBzdW1tYXJ5KGZpdDEpCgojIEZpbmQgdGhlIG1vZGVsIHNpemUgZm9yIGJlc3QgY3AsIEJJQyBhbmQgYWRqcjIKZGF0YV9mcmFtZSgKICAgIENwID0gd2hpY2gubWluKGZpdDFfc3VtbWFyeSRjcCkKICAgICwgQklDID0gd2hpY2gubWluKGZpdDFfc3VtbWFyeSRiaWMpCiAgICAsIGBBZGogUl4yYCA9IHdoaWNoLm1heChmaXQxX3N1bW1hcnkkYWRqcjIpCikgJT4lCiAgICBwYW5kZXIoY2FwdGlvbiA9ICJFeGhhdXN0aXZlIFNlYXJjaDogT3B0aW1hbCBJbmZvcm1hdGlvbiBDcml0ZXJpb24iKQpgYGAKCmBgYHtyfQpmbl9yZWdzdWJzZXRzX3Bsb3RzKGZpdDEpCmBgYAoKQmFzZWQgb24gdGhlIHRhYmxlIGFuZCBwbG90cyBhYm92ZSBmb3IgRXhoYXVzdGl2ZSBTZWFyY2gsIHRoZSBiZXN0IG1vZGVsIGlzCgokJGByIHBhc3RlMCgiWSA9ICIscGFzdGUwKGMoIlxcYmV0YV8wIiwgcGFzdGUwKCJcXGJldGFfeyIsMToxMCwifVheIiwxOjEwKSlbZml0MV9zdW1tYXJ5JHdoaWNoW3doaWNoLm1pbihmaXQxX3N1bW1hcnkkY3ApLCBdXSwgY29sbGFwc2UgPSAiICsgIikpYCQkCgoKIyMgRAoKYGBge3IgcmVzdWx0cyA9ICdhc2lzJ30KZml0MiA9IHJlZ3N1YnNldHMoeSB+IHBvbHkoeCwgMTAsIHJhdyA9IFRSVUUpLCBkYXRhID0gZGF0YV9kZiwgbnZtYXggPSAxMCwgbWV0aG9kID0gJ2JhY2t3YXJkJykKZml0Ml9zdW1tYXJ5ID0gc3VtbWFyeShmaXQyKQoKIyBGaW5kIHRoZSBtb2RlbCBzaXplIGZvciBiZXN0IGNwLCBCSUMgYW5kIGFkanIyCmRhdGFfZnJhbWUoCiAgICBDcCA9IHdoaWNoLm1pbihmaXQyX3N1bW1hcnkkY3ApCiAgICAsIEJJQyA9IHdoaWNoLm1pbihmaXQyX3N1bW1hcnkkYmljKQogICAgLCBgQWRqIFJeMmAgPSB3aGljaC5tYXgoZml0Ml9zdW1tYXJ5JGFkanIyKQopICU+JQogICAgcGFuZGVyKGNhcHRpb24gPSAiQmFja3dhcmRzIFNlYXJjaDogT3B0aW1hbCBJbmZvcm1hdGlvbiBDcml0ZXJpb24iKQpgYGAKCmBgYHtyfQpmbl9yZWdzdWJzZXRzX3Bsb3RzKGZpdDIpCmBgYAoKQmFzZWQgb24gdGhlIHRhYmxlIGFuZCBwbG90cyBhYm92ZSBmb3IgQmFja3dhcmRzIFNlYXJjaCwgdGhlIGJlc3QgbW9kZWwgaXMKCiQkYHIgcGFzdGUwKCJZID0gIixwYXN0ZTAoYygiXFxiZXRhXzAiLCBwYXN0ZTAoIlxcYmV0YV97IiwxOjEwLCJ9WF4iLDE6MTApKVtmaXQyX3N1bW1hcnkkd2hpY2hbd2hpY2gubWluKGZpdDJfc3VtbWFyeSRjcCksIF1dLCBjb2xsYXBzZSA9ICIgKyAiKSlgJCQKCmBgYHtyIHJlc3VsdHMgPSAnYXNpcyd9CmZpdDMgPSByZWdzdWJzZXRzKHkgfiBwb2x5KHgsIDEwLCByYXcgPSBUUlVFKSwgZGF0YSA9IGRhdGFfZGYsIG52bWF4ID0gMTAsIG1ldGhvZCA9ICdmb3J3YXJkJykKZml0M19zdW1tYXJ5ID0gc3VtbWFyeShmaXQzKQoKIyBGaW5kIHRoZSBtb2RlbCBzaXplIGZvciBiZXN0IGNwLCBCSUMgYW5kIGFkanIyCmRhdGFfZnJhbWUoCiAgICBDcCA9IHdoaWNoLm1pbihmaXQzX3N1bW1hcnkkY3ApCiAgICAsIEJJQyA9IHdoaWNoLm1pbihmaXQzX3N1bW1hcnkkYmljKQogICAgLCBgQWRqIFJeMmAgPSB3aGljaC5tYXgoZml0M19zdW1tYXJ5JGFkanIyKQopICU+JQogICAgcGFuZGVyKGNhcHRpb24gPSAiRm9yd2FyZCBTZWFyY2g6IE9wdGltYWwgSW5mb3JtYXRpb24gQ3JpdGVyaW9uIikKYGBgCgpgYGB7cn0KZm5fcmVnc3Vic2V0c19wbG90cyhmaXQzKQpgYGAKCkJhc2VkIG9uIHRoZSB0YWJsZSBhbmQgcGxvdHMgYWJvdmUgZm9yIEZvcndhcmRzIFNlYXJjaCwgdGhlIGJlc3QgbW9kZWwgaXMKCiQkYHIgcGFzdGUwKCJZID0gIixwYXN0ZTAoYygiXFxiZXRhXzAiLCBwYXN0ZTAoIlxcYmV0YV97IiwxOjEwLCJ9WF4iLDE6MTApKVtmaXQzX3N1bW1hcnkkd2hpY2hbd2hpY2gubWluKGZpdDNfc3VtbWFyeSRjcCksIF1dLCBjb2xsYXBzZSA9ICIgKyAiKSlgJCQKCgpXZSBzZWUgdGhhdCBmb3IgdGhlICRcYmV0YSRzIGNob3NlbiwgYmFja3dhcmRzIGFuZCBmb3J3YXJkcyBzZWFyY2ggcHJvZHVjZXMgdGhlIHNhbWUgb3B0aW1hbCBtb2RlbC4KCiMjIEUKYGBge3J9CnhtYXQgPSBtb2RlbC5tYXRyaXgoeSB+IHBvbHkoeCwgMTAsIHJhdyA9IFQpLCBkYXRhID0gZGF0YV9kZilbLCAtMV0KbW9kLmxhc3NvID0gY3YuZ2xtbmV0KHhtYXQsIFksIGFscGhhID0gMSkKYmVzdC5sYW1iZGEgPSBtb2QubGFzc28kbGFtYmRhLm1pbgoKYGBgCgpUaGUgb3B0aW1hbCB2YWx1ZSBvZiAkXGxhbWJkYSQgaXMgYHIgYmVzdC5sYW1iZGFgLgoKYGBge3J9CmZuX3Bsb3RfY3ZfZ2xtbmV0IDwtIGZ1bmN0aW9uKGN2X2dsbW5ldCwgbWFpbikgewoKICAgIGRhdGEgPC0gCiAgICAgICAgdGlkeShjdl9nbG1uZXQpICU+JSBhc190aWJibGUoKSAlPiUKICAgICAgICBtdXRhdGUobG9nX2xhbWJkYSA9IGxvZyhsYW1iZGEpKSAKICAgIAogICAgZGF0YTIgPC0KICAgICAgICBkYXRhICU+JQogICAgICAgIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgNCA9PSAwKQogICAgCiAgICBkYXRhMyA8LQogICAgICAgIGRhdGFfZnJhbWUoCiAgICAgICAgICAgIGxvZ19sYW1iZGEgPSBjKGxvZyhjdl9nbG1uZXQkbGFtYmRhLm1pbiksIGxvZyhjdl9nbG1uZXQkbGFtYmRhLjFzZSkpCiAgICAgICAgICAgICwgbmFtZSA9IGMoIk1pbiIsICIxc2UiKQogICAgICAgICkKICAgIAogICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21fZXJyb3JiYXIoZGF0YSA9IGRhdGEsIGFlcyh4ID0gbG9nX2xhbWJkYSwgeW1pbiA9IGNvbmYubG93LCB5bWF4ID0gY29uZi5oaWdoKSwgCiAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBwYWw1MzhbJ2RrZ3JheSddW1sxXV0sIGFscGhhID0gMC42KSArCiAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gZGF0YSwgYWVzKHggPSBsb2dfbGFtYmRhLCB5ID0gZXN0aW1hdGUpLCBjb2xvdXIgPSBwYWw1MzhbJ3JlZCddW1sxXV0pICsKICAgICAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBsb2coY3ZfZ2xtbmV0JGxhbWJkYS5taW4pLCBjb2xvdXIgPSBwYWw1MzhbJ2RrZ3JheSddW1sxXV0sIGFscGhhID0gMC42KSArCiAgICAgICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbG9nKGN2X2dsbW5ldCRsYW1iZGEuMXNlKSwgY29sb3VyID0gcGFsNTM4Wydka2dyYXknXVtbMV1dLCBhbHBoYSA9IDAuNikgKyAKICAgICAgICB0aGVtZV9qcmYoKSArCiAgICAgICAgbGFicyh0aXRsZSA9IG1haW4sIHggPSBleHByZXNzaW9uKGxvZyhsYW1iZGEpKSwgeSA9IGN2X2dsbW5ldCRuYW1lKSArCiAgICAgICAgZ2VvbV90ZXh0KGRhdGEgPSBkYXRhMiwgYWVzKHggPSBsb2dfbGFtYmRhLCB5ID0gSW5mLCBsYWJlbCA9IG56ZXJvKSwgdmp1c3QgPSAxLCBjb2xvdXIgPSAnIzNDM0MzQycsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGlmZWxzZShTeXMuaW5mbygpW1sndXNlciddXSAlaW4lIHVzZXJzX3YsIkRlY2ltYU1vbm9Qcm8iLCAiSGVsdmV0aWNhIiksCiAgICAgICAgICAgICAgICAgIHNpemUgPSAyLjI1KSArCiAgICAgICAgZ2VvbV9sYWJlbChkYXRhID0gZGF0YTMsIGFlcyh4ID0gbG9nX2xhbWJkYSwgeSA9IEluZiwgbGFiZWwgPSBuYW1lKSwgdmp1c3QgPSA1LCBjb2xvdXIgPSAnIzNDM0MzQycsCiAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBpZmVsc2UoU3lzLmluZm8oKVtbJ3VzZXInXV0gJWluJSB1c2Vyc192LCJEZWNpbWFNb25vUHJvIiwgIkhlbHZldGljYSIpKQp9CmBgYAoKYGBge3J9CmZuX3Bsb3RfY3ZfZ2xtbmV0KG1vZC5sYXNzbywgIkxhc3NvIE1vZGVsIG9uIFNpbXVsYXRlZCBEYXRhIikKYGBgCgoKYGBge3IgcmVzdWx0cyA9ICdhc2lzJ30KYmVzdC5tb2RlbCA8LSBnbG1uZXQoeG1hdCwgWSwgYWxwaGEgPSAxKQpjb2VmZmllY2llbnRzIDwtIHByZWRpY3QoYmVzdC5tb2RlbCwgcyA9IGJlc3QubGFtYmRhLCB0eXBlID0gImNvZWZmaWNpZW50cyIpCmNvZWZmaWVjaWVudHNfZGYgPC0KICAgIGRhdGFfZnJhbWUoCiAgICBjb2VmZmllY2llbnQgPSBuYW1lcyhjb2VmZmllY2llbnRzWywgMV0pCiAgICAsIGVzdGltYXRlID0gY29lZmZpZWNpZW50c1ssIDFdCiAgICApICU+JQogICAgbXV0YXRlKGVzdGltYXRlID0gaWZlbHNlKGVzdGltYXRlID09IDAsIE5BLCBlc3RpbWF0ZSkpICU+JQogICAgbXV0YXRlKGNvZWZmaWVjaWVudCA9IHBhc3RlMCgiJFxcYmV0YV97Iiwgcm93X251bWJlcigpIC0gMSwgIn0kIikpCgpiZXRhc19hYm92ZV8zIDwtIAogICAgY29lZmZpZWNpZW50c19kZiAlPiUgCiAgICBmaWx0ZXIoaXMubmEoZXN0aW1hdGUpICYgcm93X251bWJlcigpID4gNCkgJT4lIAogICAgc2VsZWN0KGNvZWZmaWVjaWVudCkgJT4lIAogICAgdW5saXN0KCkgJT4lIAogICAgc3RyaW5ncjo6c3RyX2V4dHJhY3QoIihcXGQrKSIpCiAgICAKY29lZmZpZWNpZW50c19kZiAlPiUKICAgIHBhbmRlcihtaXNzaW5nID0gIiIpCmBgYAoKTGFzc28gcGlja3MgYHIgcGFzdGUwKHBhc3RlMCgiJFhfeyIsYmV0YXNfYWJvdmVfMywifSQiKSwgY29sbGFwc2UgPSAiLCIpYCBvdmVyICRYXzMkLgoKIyMgRgoKV2Ugc2VsZWN0ICRcYmV0YV83ID0gNyQgYW5kIHJlZ3N1YnNldHMgd2l0aCBFeGhhdXN0aXZlIFNlYXJjaC4KCmBgYHtyfQpiZXRhNyA9IDcKClkyID0gYmV0YTAgKyBiZXRhNyAqIFheNyArIGVwcwpgYGAKCgpgYGB7cn0KZGF0YV9kZjIgPC0gZGF0YV9mcmFtZSh5ID0gWTIsIHggPSBYKQpmaXQ3ID0gcmVnc3Vic2V0cyh5IH4gcG9seSh4LCAxMCwgcmF3ID0gVFJVRSksIGRhdGEgPSBkYXRhX2RmMiwgbnZtYXggPSAxMCwgbWV0aG9kID0gJ2V4aGF1c3RpdmUnKQoKZm5fcmVnc3Vic2V0c19wbG90cyhmaXQ3KQpgYGAKCkZvciBhIG1vZGVsIHdpdGggb25lIHByZWRpY3RvciwgdGhlIGVzdGltYXRlcyBpcyB2ZXJ5IGNsb3NlIHRvIHRoZSBhY3R1YWwgY29lZmZpY2llbnRzOgoKJCRZID0gYHIgY29lZihmaXQ3LCAxKVtbMV1dYCArIGByIGNvZWYoZml0NywgMSlbWzJdXWBYXjckJAoKTm93IHVzaW5nIGxhc3NvLAoKYGBge3J9CnhtYXQyID0gbW9kZWwubWF0cml4KHkgfiBwb2x5KHgsIDEwLCByYXcgPSBUKSwgZGF0YSA9IGRhdGFfZGYyKVssIC0xXQptb2QubGFzc28yID0gY3YuZ2xtbmV0KHhtYXQyLCBZMiwgYWxwaGEgPSAxKQpiZXN0LmxhbWJkYTIgPSBtb2QubGFzc28yJGxhbWJkYS5taW4KZm5fcGxvdF9jdl9nbG1uZXQobW9kLmxhc3NvMiwgIkxhc3NvIE1vZGVsIG9uIFNpbXVsYXRlZCBEYXRhIikKYGBgCgoKYGBge3IgcmVzdWx0cz0gJ2FzaXMnfQpiZXN0Lm1vZGVsMiA9IGdsbW5ldCh4bWF0MiwgWSwgYWxwaGEgPSAxKQpjb2VmZmllY2llbnRzMiA9IHByZWRpY3QoYmVzdC5tb2RlbDIsIHMgPSBiZXN0LmxhbWJkYTIsIHR5cGUgPSAiY29lZmZpY2llbnRzIikKY29lZmZpZWNpZW50c19kZjIgPC0KICAgIGRhdGFfZnJhbWUoCiAgICBjb2VmZmllY2llbnQgPSBuYW1lcyhjb2VmZmllY2llbnRzMlssIDFdKQogICAgLCBlc3RpbWF0ZSA9IGNvZWZmaWVjaWVudHMyWywgMV0KICAgICkgJT4lCiAgICBtdXRhdGUoZXN0aW1hdGUgPSBpZmVsc2UoZXN0aW1hdGUgPT0gMCwgTkEsIGVzdGltYXRlKSkgJT4lCiAgICBtdXRhdGUoY29lZmZpZWNpZW50ID0gcGFzdGUwKCIkXFxiZXRhX3siLCByb3dfbnVtYmVyKCkgLSAxLCAifSQiKSkKCmJldGFzX2Fib3ZlXzMgPC0gY29lZmZpZWNpZW50c19kZjIgJT4lIGZpbHRlcihpcy5uYShlc3RpbWF0ZSkgJiByb3dfbnVtYmVyKCkgPiAzKSAlPiUgc2VsZWN0KGNvZWZmaWVjaWVudCkgJT4lIHVubGlzdCgpICU+JSBzdHJpbmdyOjpzdHJfZXh0cmFjdCgiKFxcZCspIikKICAgIApjb2VmZmllY2llbnRzX2RmMiAlPiUKICAgIHBhbmRlcihtaXNzaW5nID0gIiIpCmBgYAoKTGFzc28gb25seSBzZWxlY3RzIHRoZSBpbnRlcmNlcHQgdGVybSBhbmQgbm90ICRYXjckIGFuZCB0aGUgaW50ZXJjZXB0IGlzIHF1aXRlIG9mZi4KCiMgQ3JpbWUgRGF0YQoKIyMgUGFydCAxCgpUaGUgbWFwIGJlbG93IHNob3dzIHRoZSBtZWFuIG9mIHRoZSBgcGN0LnVuZW1wbG95ZWRgIHZhcmlhYmxlIGluIGBDcmltZURhdGEuY3N2YC4gVGhpcyBtZXRyaWMgZG9lcyBub3QgbWFrZSBtdWNoIHNlbnNlIGJlY2F1c2UgaXQgdGhlIGF2ZXJhZ2Ugb2YgYSBwZXJjZW50IG9mIGEgc3Vic2V0IG9mIGNvbW11bml0aWVzIGluIHRoZSBVUy4gVGhpcyBpcyB0byBkZW1vbnN0cmF0ZSB0aGUgZnVuY3Rpb25hbGl0eS4KCmBgYHtyfQpjcmltZV9kYXRhIDwtIHJlYWRyOjpyZWFkX2NzdihwYXN0ZTAoZGF0YV9kaXIsICJDcmltZURhdGEuY3N2IiksIG5hID0gYygiIiwiPyIpKQoKCgpkYXRhKCJzdGF0ZSIpCmRhdGEoInVzZ2VvanNvbiIpCgpkZiA8LSAKICAgIGRhdGFfZnJhbWUoU3RhdGUgPSByb3duYW1lcyhzdGF0ZS54NzcpLCBhYmIgPSBzdGF0ZS5hYmIpICU+JSAKICAgIGlubmVyX2pvaW4oCiAgICAgICAgY3JpbWVfZGF0YSAlPiUKICAgICAgICAgICAgZ3JvdXBfYnkoc3RhdGUpICU+JQogICAgICAgICAgICBzdW1tYXJpc2UobWVhbl9wY3QudW5lbXBsb3llZCA9IG1lYW4ocGN0LnVuZW1wbG95ZWQpKQogICAgICAgICwgYnkgPSBjKCJhYmIiID0gInN0YXRlIikKICAgICkKCgpoaWdoY2hhcnQoKSAlPiUKICBoY190aXRsZSh0ZXh0ID0gIk1lYW4gb2YgUGVyY2VudGFnZSBvZiBVbmVtcGxveWVkIikgJT4lCiAgaGNfc3VidGl0bGUodGV4dCA9ICJTb3VyY2U6IENyaW1lRGF0YS5jc3YiKSAlPiUKICBoY19hZGRfc2VyaWVzX21hcCh1c2dlb2pzb24sIGRmLCBuYW1lID0gIlBlciBDYXBpdGEgSW5jb21lICgxOTc0KSIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSAibWVhbl9wY3QudW5lbXBsb3llZCIsIGpvaW5CeSA9IGMoIndvZW5hbWUiLCAiU3RhdGUiKSwKICAgICAgICAgICAgICAgICAgICBkYXRhTGFiZWxzID0gbGlzdChlbmFibGVkID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQgPSAne3BvaW50LnByb3BlcnRpZXMucG9zdGFsY29kZX0nKSkgJT4lCiAgaGNfY29sb3JBeGlzKG1pbiA9IG1pbihkZiRJbmNvbWUpKSAlPiUKICBoY19sZWdlbmQodmFsdWVEZWNpbWFscyA9IDAsIHZhbHVlU3VmZml4ID0gIiUiKSAlPiUKICBoY190b29sdGlwKHZhbHVlUHJlZml4ID0gIiUiLCB2YWx1ZURlY2ltYWxzID0gMSkgJT4lCiAgaGNfbWFwTmF2aWdhdGlvbihlbmFibGVkID0gVFJVRSkgJT4lCiAgaGNfY3JlZGl0cyhlbmFibGVkID0gVFJVRSwgdGV4dCA9ICJJbnNwaXJlZCBieSBodHRwOi8vamt1bnN0LmNvbS9oaWdoY2hhcnRlci9oaWdobWFwcy5odG1sIiwgCiAgICAgICAgICAgICBocmVmID0gImh0dHA6Ly9qa3Vuc3QuY29tL2hpZ2hjaGFydGVyL2hpZ2htYXBzLmh0bWwiKQpgYGAKCgpUaGUgbWFwIGJlbG93IHNob3dzIHRoZSBwb3B1bGF0aW9uIGJ5IGNvdW50eSBmcm9tIHRoZSBgQ3JpbWVEYXRhLmNzdmAgZGF0YXNldC4gVGhlcmUgYXJlIG1hbnkgY29tbXVuaXRpZXMgaW4gdGhlIGRhdGFzZXQgdGhhdCBhcmUgbWlzc2luZyBjb3VudHkgY29kZXMgYW5kIG1hbnkgY291bnRpZXMgYXJlIG1pc3NpbmcgYWxsIHRoZSBjb21tdW5pdGllcy4gQWdhaW4sIHRoaXMgaXMgdG8gZGVtb25zdHJhdGUgdGhlIGZ1bmN0aW9uYWxpdHkuCgpgYGB7cn0KZGF0YSgidXNjb3VudHlnZW9qc29uIikKCmNyaW1lX2RhdGEyIDwtIAogICAgY3JpbWVfZGF0YSAlPiUKICAgIGZpbHRlcihjb3VudHkgIT0gIj8iKSAlPiUKICAgIGdyb3VwX2J5KHN0YXRlLCBjb3VudHkpICU+JQogICAgc3VtbWFyaXNlKHBvcHVsYXRpb24gPSBzdW0ocG9wdWxhdGlvbikpICU+JQogICAgbXV0YXRlKGNvZGUgPSBwYXN0ZTAoJ3VzLScsdG9sb3dlcihzdGF0ZSksJy0nLCBzdHJpbmdyOjpzdHJfcGFkKGNvdW50eSwgMywgc2lkZSA9ICJsZWZ0IiwgcGFkID0gIjAiKSkpICU+JQogICAgc2VsZWN0KHN0YXRlLCBjb3VudHksIGNvZGUsIHBvcHVsYXRpb24pCgpuIDwtIDE2CmRzdG9wcyA8LSBkYXRhLmZyYW1lKHEgPSAwOm4vbiwgYyA9IHJldihzdWJzdHJpbmcodmlyaWRpcyhuICsgMSwgb3B0aW9uID0gIkIiKSwgMCwgNykpKQpkc3RvcHMgPC0gbGlzdF9wYXJzZTIoZHN0b3BzKQoKaGlnaGNoYXJ0KCkgJT4lIAogIGhjX3RpdGxlKHRleHQgPSAiUG9wdWxhdGlvbiBieSBDb3VudHkiKSAlPiUKICBoY19zdWJ0aXRsZSh0ZXh0ID0gIlNvdXJjZTogQ3JpbWVEYXRhLmNzdiIpICU+JQogIGhjX2FkZF9zZXJpZXNfbWFwKG1hcCA9IHVzY291bnR5Z2VvanNvbiwgZGYgPSBjcmltZV9kYXRhMiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9ICJwb3B1bGF0aW9uIiwgam9pbkJ5ID0gYygiY29kZSIsICJjb2RlIiksCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJQb3B1bGF0aW9uIiwgYm9yZGVyV2lkdGggPSAwLjEpICU+JSAKICBoY19jb2xvckF4aXMoc3RvcHMgPSBkc3RvcHMsIG1pbiA9IG1pbihjcmltZV9kYXRhMiRwb3B1bGF0aW9uKSkgJT4lIAogIGhjX2xlZ2VuZChsYXlvdXQgPSAidmVydGljYWwiLCByZXZlcnNlZCA9IFRSVUUsCiAgICAgICAgICAgIGZsb2F0aW5nID0gVFJVRSwgYWxpZ24gPSAicmlnaHQiKSAlPiUgCiAgaGNfbWFwTmF2aWdhdGlvbihlbmFibGVkID0gVFJVRSwgYWxpZ24gPSAicmlnaHQiKSAlPiUgCiAgaGNfdG9vbHRpcCh2YWx1ZURlY2ltYWxzID0gMCkgJT4lCiAgaGNfY3JlZGl0cyhlbmFibGVkID0gVFJVRSwgdGV4dCA9ICJJbnNwaXJlZCBieSBodHRwOi8vamt1bnN0LmNvbS9oaWdoY2hhcnRlci9oaWdobWFwcy5odG1sIiwgCiAgICAgICAgICAgICBocmVmID0gImh0dHA6Ly9qa3Vuc3QuY29tL2hpZ2hjaGFydGVyL2hpZ2htYXBzLmh0bWwiKQpgYGAKCiMjIFBhcnQgMgoKYGBge3J9CnZhcl9uYW1lc19vdXQgPC0gYygibnVtLnVyYmFuIiwib3RoZXIucGVyY2FwIiwibnVtLnVuZGVycG92IiwibnVtLnZhY2FudC5ob3VzZSIsIm51bS5tdXJkZXJzIiwibnVtLnJhcGVzIiwKICAgICAgICAgICAgICAgICAgICJudW0ucm9iYmVyaWVzIiwibnVtLmFzc2F1bHRzIiwibnVtLmJ1cmdsYXJpZXMiLCJudW0ubGFyY2VuaWVzIiwibnVtLmF1dG90aGVmdHMiLCJudW0uYXJzb25zIikKCm5hbWVzX290aGVyX2NyaW1lcyA8LSBjKCJtdXJkZXIucGVycG9wIiwgInJhcGVzLnBlcnBvcCIsInJvYmJlcmllcy5wZXJwb3AiLCJhc3NhdWx0cy5wZXJwb3AiLCJub252aW9sZW50Y3JpbWVzLnBlcnBvcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICJidXJnbGFyaWVzLnBlcnBvcCIsImxhcmNlbmllcy5wZXJwb3AiLCJhdXRvdGhlZnRzLnBlcnBvcCIsImFyc29ucy5wZXJwb3AiKQoKZGF0YV9jYWZsIDwtIAogICAgY3JpbWVfZGF0YSAlPiUgCiAgICBzZWxlY3QoYygyLDY6MTAzLDEyMSwxMjIsMTIzLCAxMzA6MTQ3KSkgJT4lCiAgICBzZWxlY3QoLW9uZV9vZihjKHZhcl9uYW1lc19vdXQsIG5hbWVzX290aGVyX2NyaW1lcykpKSAlPiUKICAgIGZpbHRlcihzdGF0ZSAlaW4lIGMoIkZMIiwiQ0EiKSkgJT4lCiAgICBmaWx0ZXIoY29tcGxldGUuY2FzZXMoLikpCmBgYAoKRnJvbSB0aGUgYENyaW1lRGF0YS5jc3ZgIGRhdGFzZXQgd2UgZXh0cmFjdCB0aGUgZGF0YSBmb3Igb25seSB0aGUgc3RhdGVzIENBIGFuZCBGTC4gSW4gYWRkaXRpb24sIHdlIHNlbGVjdCBvbmx5IHZhcmlhYmxlcyBmcm9tIGZvbGxvd2luZyB0aGUgcHJvY2VzcyB1c2VkIGluIExlY3R1cmUgNiBhbmQgcmVtb3ZlIG1pc3NpbmcgdmFsdWVzLiBBcyBhIHJlc3VsdCB3ZSBoYXZlIGByIG5yb3coZGF0YV9jYWZsKWAgb2JzZXJ2YXRpb24gYW5kIGByIG5jb2woZGF0YV9jYWZsKWAgdmFyaWFibGVzLgoKIyMjIChBKQoKV2UgcGVyZm9ybSAxMC1mb2xkIGNyb3NzLXZhbGlkYXRpb24gZm9yIGdsbW5ldCB3aXRoICRcYWxwaGEkID0gMC45OS4gCgpgYGB7cn0KeF9tYXRyaXhfZmxjYSA8LSBtb2RlbC5tYXRyaXgodmlvbGVudGNyaW1lcy5wZXJwb3AgfiAuLCBkYXRhID0gZGF0YV9jYWZsKVssIC0xXQoKeV92aW9sZW50X2NyaW1lcyA8LSAKICAgIGRhdGFfY2FmbCAlPiUgCiAgICBzZWxlY3QodmlvbGVudGNyaW1lcy5wZXJwb3ApICU+JSAKICAgIHVubGlzdCgpCgpmaXRfY2FmbF8xIDwtIGN2LmdsbW5ldCh4X21hdHJpeF9mbGNhLCB5X3Zpb2xlbnRfY3JpbWVzLCBhbHBoYSA9IC45OSwgbmZvbGRzID0gMTApCgpmbl9wbG90X2N2X2dsbW5ldChmaXRfY2FmbF8xLCBleHByZXNzaW9uKCJGTCAmIENBIENyaW1lIERhdGE6IEVsYXN0aWNOZXQgIn4gYWxwaGEgfiI9IDAuOTkiKSkKYGBgCgpXZSBzZWUgdGhhdCB0aGUgbWVhbiBjcm9zcy12YWxpZGF0ZWQgZXJyb3IgaXMgbWluaW1pemVkIHdoZW4gJFxsYW1iZGEgPSBlXntgciBsb2coZml0X2NhZmxfMSRsYW1iZGEubWluKWB9ID0gYHIgZml0X2NhZmxfMSRsYW1iZGEubWluYCQgYW5kIHRoZXJlIGFyZSBgciB0aWR5KGZpdF9jYWZsXzIpICU+JSBmaWx0ZXIoZXN0aW1hdGUgIT0gMCAmIHRlcm0gIT0gIihJbnRlcmNlcHQpIikgJT4lIG5yb3coKWAgbm9uLXplcm8gZXN0aW1hdGVzIG9mICRcYmV0YV9pJC4gV2Ugd2lsbCB1c2UgdGhpcyB3aXRoIGdsbW5ldCB0byBjcmVhdGUgbmV3IGZpdC4KCmBgYHtyIHJlc3VsdHMgPSAnYXNpcyd9CmZpdF9jYWZsXzIgPC0gZ2xtbmV0KHhfbWF0cml4X2ZsY2EsIHlfdmlvbGVudF9jcmltZXMsIGFscGhhID0gLjk5LCBsYW1iZGEgPSBmaXRfY2FmbF8xJGxhbWJkYS5taW4pCgpyZWxldmVudF92YXJzIDwtIAogICAgdGlkeShmaXRfY2FmbF8yKSAlPiUgCiAgICBmaWx0ZXIoZXN0aW1hdGUgIT0gMCAmIHRlcm0gIT0gIihJbnRlcmNlcHQpIikKCgpyZWdzdWJzZXRzX2NhZmwxIDwtIAogICAgcmVnc3Vic2V0cyhhcy5mb3JtdWxhKHBhc3RlMCgidmlvbGVudGNyaW1lcy5wZXJwb3AgfiAiLCBwYXN0ZTAocmVsZXZlbnRfdmFycyR0ZXJtLCBjb2xsYXBzZSA9ICIgKyAiKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudm1heCA9IDE1LCBtZXRob2QgPSAiZXhoYXVzdGl2ZSIsIGRhdGEgPSBkYXRhX2NhZmwpCgpzdW1tYXJ5KHJlZ3N1YnNldHNfY2FmbDEpJG91dG1hdCAlPiUgCiAgICBhc190aWJibGUoKSAlPiUgCiAgICBwYW5kZXIobWlzc2luZyA9ICIiLCBzcGxpdC50YWJsZSA9IEluZikKYGBgICAgIAoKVGhlIHRhYmxlIGFib3ZlIHNob3dzIHdoaWNoIG9mIHRoZSBmaXZlIHZhcmFpYmxlcyB3b3VsZCBiZSBwcmVzZW50IGluIHRoZSBvcHRpbWFsIG1vZGVsIGF0IGVhY2ggIyBvZiBwcmVkaWN0b3JzLiBGb3IgZXhhbXBsZSwgbm90ZSB0aGF0IGBwY3QuaG91c2UudmFjYW50YCB3b3VsZCBub3QgYmUgcHJlc2VudCBpZiBvbmx5IDQgdmFyaWFibGVzIHdlcmUgdXNlZC4gV2UgY3JlYXRlIGEgcGxvdCB0byBzaG93IHRoZSBvcHRpbWFsICMgb2YgcHJlZGljdG9ycyBiYXNlZCBvbiBDcCwgQklDLCBhbmQgQWRqdXN0ZWQgJFJeMiQuCgoKYGBge3J9CmZuX3JlZ3N1YnNldHNfcGxvdHMocmVnc3Vic2V0c19jYWZsMSkKYGBgCgpUaGUgb3B0aW1hbCBtb2RlbCBiYXNlZCBvbnQgdGhlIEJJQyBjcml0ZXJpYSB1c2VzIDQgcHJlZGljdG9ycywgYnV0IGJhc2VkIG9uIENwIHRoZSBvcHRpbWFsIG1vZGVsIHdvdWxkIGluY2x1ZGUgNSBwcmVkaWN0b3JzLiBXZSB3aWxsIG9ubHkgY3JlYXRlIGEgbW9kZWwgaWYgdGhlICRwJC12YWx1ZXMgYXJlIGxlc3MgdGhhbiAwLjA1LiBXZSdsbCBjcmVhdGUgdGhpcyBtb2RlbCBhbmQgbm90ZSB0aGF0ICoqYWxsIHZhcmlhYmxlcyBhcmUgc2lnbmlmaWNhbnQgYXQgdGhlIDAuMDUgbGV2ZWwqKi4gSG93ZXZlciwgdGhlIHZhcmlhYmxlIGBwY3QuaG91c2UudmFjYW50YCBpcyBqdXN0IGJhcmVseSBzaWduaWZpY2FudC4KCgpgYGB7ciByZXN1bHRzID0gJ2FzaXMnfQpmaXRfY2FmbF8zIDwtIGxtKGFzLmZvcm11bGEocGFzdGUwKCJ2aW9sZW50Y3JpbWVzLnBlcnBvcCB+ICIsIAogICAgICAgICAgICAgICAgICAgIHBhc3RlMChzdW1tYXJ5KHJlZ3N1YnNldHNfY2FmbDEpJG9iaiR4bmFtZXNbLTFdLCBjb2xsYXBzZSA9ICIgKyAiKSkpLCBkYXRhID0gZGF0YV9jYWZsKQp0aWR5KGZpdF9jYWZsXzMpICU+JSBhcnJhbmdlKHAudmFsdWUpICU+JSBwYW5kZXIoKQpgYGAKCldlIHJlbW92ZSBgcGN0LmhvdXNlLnZhY2FudGAsIGZpdCBhbm90aGVyIGxpbmVhciBtb2RlbCwgYW5kIHNlZSBhbGwgdGhlIHZhcmlhYmxlcyBhcmUgc2lnbmlmY2FudCBhdCBhIDAuMDEgY29uZmlkZW5jZSBsZXZlbC4gCgpgYGB7ciByZXN1bHRzID0gJ2FzaXMnfQpjYWZsX3Rlcm1zIDwtIAogICAgdGlkeShmaXRfY2FmbF8zKSAlPiUKICAgIGZpbHRlcih0ZXJtICE9ICIoSW50ZXJjZXB0KSIpICU+JQogICAgYXJyYW5nZShwLnZhbHVlKSAlPiUKICAgIHNlbGVjdCh0ZXJtKSAlPiUKICAgIHVubGlzdCgpCgpmaXRfY2FmbF80IDwtIGxtKGFzLmZvcm11bGEocGFzdGUwKCJ2aW9sZW50Y3JpbWVzLnBlcnBvcCB+ICIsIHBhc3RlMChjYWZsX3Rlcm1zWy01XSwgY29sbGFwc2UgPSAiICsgIikpKSwgZGF0YSA9IGRhdGFfY2FmbCkKCnRpZHlfY2FmbF8xIDwtIHRpZHkoZml0X2NhZmxfNCkgJT4lIGFycmFuZ2UocC52YWx1ZSkKdGlkeV9jYWZsXzEgJT4lIHBhbmRlcigpCmBgYAoKVGhvdWdoIHRoZSByZXF1aXJlbWVudHMgb2YgdGhlIHByb2JsZW0gc3RhdGUgdG8gaW5jbHVkZSB2YXJpYWJsZXMgd2l0aCAkcCQtdmFsdWVzIGxlc3MgdGhhbiAwLjA1LCBpbiBvcmRlciB0byBjcmVhdGUgYSBwYXJzaW1vbmlvdXMgbGluZWFyIG1vZGVsIHdlIHdpbGwgZXhjbHVkZSB0aGUgdmFyaWFibGUgYHBjdC5ob3VzZS52YWNhbnRgIGFzIHRoaXMgZG9lcyBwcm92aWRlIG11Y2ggbW9yZSBleHBsYW5hdG9yeSBwb3dlci4gVGhlIEJJQyBjcml0ZXJpYSwgd2hpY2ggaGFzIGEgbXVjaCBoYXJzaGVyIGNvbXBsZXhpdHkgcGVuYWx0eSB0aGFuIENwLCBpbmRpY2F0ZXMgNCB2YXJpYWJsZXMgaXMgb3B0aW1hbCBhbmQgd2Ugd2lsbCBmb2xsb3cgdGhpcyBoZXVyaXN0aWMuIE1vcmVvdmVyLCB3ZSBiZWxpZXZlIGluIHRoZSBtYXhpbSB0aGF0IHNpbXBsZXIgbW9kZWxzIGFyZSBhbHdheXMgYmV0dGVyLgoKVGhlIGZpbmFsIG1vZGVsIGlzIAoKJCR2aW9sZW50Y3JpbWVzLnBlcnBvcCA9IGByIHRpZHlfY2FmbF8xWzEsIDJdYCArIApgciB0aWR5X2NhZmxfMVsyLCAyXWBgciB0aWR5X2NhZmxfMVsyLCAxXWAgKwpgciB0aWR5X2NhZmxfMVszLCAyXWBgciB0aWR5X2NhZmxfMVszLCAxXWAgKwpgciB0aWR5X2NhZmxfMVs0LCAyXWBgciB0aWR5X2NhZmxfMVs0LCAxXWAgKyBcXApgciB0aWR5X2NhZmxfMVs1LCAyXWBgciB0aWR5X2NhZmxfMVs1LCAxXWAkJAoKCkhvbGRpbmcgYWxsIG90aGVyIHZhcmlhYmxlcyBjb25zdGFudCBpbiBhIGNvbW11bml0eSwKCisgQW4gaW5jcmVhc2UgaW4gMSUgb2YgKipmYW1pbGllcyB3aXRoIGtpZHMgYW5kIDIgcGFyZW50cyoqLCBkZWNyZWFzZXMgdGhlIG51bWJlciBvZiB2aW9sZW50IGNyaW1lcyBwZXIgcGVyc29uIGJ5ICoqYHIgdGlkeV9jYWZsXzFbMiwgMl1gKiouCisgQW4gaW5jcmVhc2UgaW4gMSUgb2YgKipmYW1pbGllcyB3aXRoIGtpZHMgd2l0aCB1bm1hcnJpZWQgcGFyZW50cyoqLCBpbmNyZWFzZXMgdGhlIG51bWJlciBvZiB2aW9sZW50IGNyaW1lcyBwZXIgcGVyc29uIGJ5ICoqYHIgdGlkeV9jYWZsXzFbMywgMl1gKiouCisgQW4gaW5jcmVhc2UgaW4gMSUgb2YgKipibGFjayByZXNpZGVudHMqKiwgaW5jcmVhc2VzIHRoZSBudW1iZXIgb2YgdmlvbGVudCBjcmltZXMgcGVyIHBlcnNvbiBieSAqKmByIHRpZHlfY2FmbF8xWzQsIDJdYCoqLgorIEFuIGluY3JlYXNlIGluIDElIG9mICoqdGhlIG51bWJlciBvZiBzaGVsdGVycyoqLCBpbmNyZWFzZXMgdGhlIG51bWJlciBvZiB2aW9sZW50IGNyaW1lcyBwZXIgcGVyc29uIGJ5ICoqYHIgdGlkeV9jYWZsXzFbNSwgMl1gKiouCgojIyMgKEIpCgpJbiBvcmRlciB0byBjcm9zcy12YWxpZGF0ZSBsYW1iZGFzIGFuZCBhbHBoYXMsIHdlIHVzZSB0aGUgW2NhcmV0XShodHRwOi8vdG9wZXBvLmdpdGh1Yi5pby9jYXJldC9pbmRleC5odG1sKSBwYWNrYWdlIHdoaWNoIGdlbmVyYWxpemVzIG1vZGVsIHRyYWluaW5nIGFuZCB0ZXN0aW5nLiBUd28gaW1wb3J0YW50IGlucHV0cyB0byB0aGUgYHRyYWluYCBmdW5jdGlvbiBhcmUgYSBgdHJhaW5Db250cm9sYCBhbmQgYHR1bmVHcmlkYC4gSW4gdGhlIGB0cmFpbkNvbnRyb2xgIHdlIHNwZWNpZnkgMTAtZm9sZCBjcm9zcy12YWxpZGF0aW9uLCByZXBlYXRlZCA1IHRpbWVzLiBBcyBib3RoIGxhbWJkYXMgYW5kIGFscGhhcyBhcmUgc3RhdGlzdGljcyBpdCBpcyBpbXBvcnRhbnQgdG8gdXNlIHJlcGVhdGVkIGNyb3NzLXZhbGlkYXRpb24gaW4gdGhpcyBzY2VuYXJpby4gSW4gdGhlIGB0dW5lR3JpZGAgd2Ugc3BlY2lmeSB3aGljaCBhbHBoYXMgYW5kIGxhbWJkYXMgdG8gYXR0ZW1wdC4gRm9yIGFscGhhcywgd2UgdXNlIGEgc2VxdWVuY2UgYmV0d2VlbiAwIGFuZCAxIGFuZCBmb3IgbGFtYmRhcyB3ZSB1c2UgdGhlIG9yaWdpbmFsIGxhbWJkYXMgZm91bmQgaW4gcGFydCAoQSkuCgpXZSB0aGVuIHBsb3QgdGhlIGFscGhhIGFuZCBsYW1iZGEgY29tYmluYXRpb25zIGFnYWluc3QgdGhlIG1lYW4tc3F1YXJlZCBlcnJvciAoTVNFKSBhbmQgaGlnaGxpZ2h0IHRoZSBjb21iaW5hdGlvbiB0aGF0IG1pbmltaXplcyB0aGUgTVNFLgoKCmBgYHtyfQpnbG1uZXRUckNvbnRyb2wgPC0gCiAgICB0cmFpbkNvbnRyb2woCgkJICBtZXRob2QgPSAicmVwZWF0ZWRDViIKCQksIG51bWJlciA9IDEwCgkJLCByZXBlYXRzID0gNQoJKQoKZ2xtbmV0R3JpZCA8LSAKICAgIGV4cGFuZC5ncmlkKAogICAgICAgICAgYWxwaGEgPSBzZXEoMCwgMSwgMC4xKQogICAgICAgICwgbGFtYmRhID0gZml0X2NhZmxfMSRsYW1iZGEKICAgICkKCnNldC5zZWVkKDQyKQptb2RlbCA8LSAKICAgIHRyYWluKAogICAgICAgICAgdmlvbGVudGNyaW1lcy5wZXJwb3AgfiAuCiAgICAgICAgLCBkYXRhID0gZGF0YV9jYWZsCiAgICAgICAgLCBtZXRob2QgPSAnZ2xtbmV0JwogICAgCSwgdHVuZUdyaWQgPSBnbG1uZXRHcmlkCiAgICAJLCB0ckNvbnRyb2wgPSBnbG1uZXRUckNvbnRyb2wKICAgICkKCm1vZGVsX3Jlc3VsdHMgPC0gCiAgICBtb2RlbCRyZXN1bHRzICU+JSAKICAgICAgICBhc190aWJibGUoKSAlPiUKICAgICAgICBtdXRhdGUoCiAgICAgICAgICAgIGxvZ19sYW1iZGEgPSBsb2cobGFtYmRhKQogICAgICAgICAgICAsIGFscGhhID0gcm91bmQoYWxwaGEsIDEpCiAgICAgICAgICAgICwgTVNFID0gUk1TRV4yCiAgICAgICAgKQoKbWluaW1pemVkIDwtIG1vZGVsX3Jlc3VsdHMgJT4lIGFycmFuZ2UoUk1TRSkgJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgPT0gMSkKCmRhdGFfY2FmbDIgPC0KICAgIGRhdGFfY2FmbCAlPiUKICAgIHNlbGVjdChvbmVfb2YoYygidmlvbGVudGNyaW1lcy5wZXJwb3AiKSwgcHJlZGljdG9ycyhtb2RlbCkpKQoKeF9tYXRyaXhfZmxjYTIgPC0gbW9kZWwubWF0cml4KHZpb2xlbnRjcmltZXMucGVycG9wIH4gLiwgZGF0YSA9IGRhdGFfY2FmbDIpWywgLTFdCgpnbG1uZXRfZml0MSA8LSBnbG1uZXQoeF9tYXRyaXhfZmxjYTIsIHlfdmlvbGVudF9jcmltZXMsIGFscGhhID0gbW9kZWwkYmVzdFR1bmUkYWxwaGEsIGxhbWJkYSA9IG1vZGVsJGJlc3RUdW5lJGxhbWJkYSkKCnRpZHlfY2FmbF8yIDwtIHRpZHkoZ2xtbmV0X2ZpdDEpCgpnZ3Bsb3QoKSArCnRoZW1lX2pyZigpICsgCmdlb21fbGluZShkYXRhID0gbW9kZWxfcmVzdWx0cywgYWVzKHggPSBsb2dfbGFtYmRhLCB5ID0gTVNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBhcy5mYWN0b3IoYWxwaGEpLCBjb2xvdXIgPSBhcy5mYWN0b3IoYWxwaGEpKSkgKwpnZW9tX3BvaW50KGFlcyh4ID0gbWluaW1pemVkJGxvZ19sYW1iZGEsIHkgPSBtaW5pbWl6ZWQkTVNFKSwgY29sb3VyID0gcGFsNTM4Wydka2dyYXknXVtbMV1dKSArCmxhYnModGl0bGUgPSAiQ3Jvc3MgVmFsaWRhdGlvbiBvZiBBbHBoYSBhbmQgTGFtYmRhIiwgeCA9IGV4cHJlc3Npb24obG9nKGxhbWJkYSkpLCAKICAgICB5ID0gIk1lYW4tU3F1YXJlZCBFcnJvciAoUmVwZWF0ZWQgQ3Jvc3MtVmFsaWRhdGlvbikiKSArCnNjYWxlX2NvbG91cl9kaXNjcmV0ZShndWlkZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9IGV4cHJlc3Npb24oYWxwaGEpKSkgKwpnZW9tX3NlZ21lbnQoYWVzKHggPSBtaW5pbWl6ZWQkbG9nX2xhbWJkYSwgeGVuZCA9IG1pbmltaXplZCRsb2dfbGFtYmRhLCB5ID0gNTAwXjIsIHllbmQgPSAzOTBeMiksIAogICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMDMsICJucGMiKSksIGNvbG91ciA9IHBhbDUzOFsnZGtncmF5J11bWzFdXSwgYWxwaGEgPSAwLjUpICsKZ2VvbV9sYWJlbChkYXRhID0gZGF0YV9mcmFtZSh4ID0gbWluaW1pemVkJGxvZ19sYW1iZGEsIHkgPSA1MDBeMiwgbGFiZWwgPSAiQWxwaGEgYW5kIExhbWJkYVxudGhhdCBNaW5pbWl6ZSBNU0UiKSwgCiAgICBhZXMoeCA9IHgsIHkgPSB5LCBsYWJlbCA9IGxhYmVsKSwgY29sb3VyID0gcGFsNTM4Wydka2dyYXknXVtbMV1dLCBmYW1pbHkgPSAiRGVjaW1hTW9ub1BybyIpCmBgYAoKVGhpcyBtb2RlbCB1c2VzIGByIGxlbmd0aChwcmVkaWN0b3JzKG1vZGVsKSlgIHByZWRpY3RvcnM6IGByIHByZWRpY3RvcnMobW9kZWwpICU+JSBwYW5kZXIoKWAuIFRoZSBvcHRpbWFsIHBhcmFtZXRlcnMgYXJlCgokJFxhbHBoYSA9IGByIG1vZGVsJGJlc3RUdW5lJGFscGhhYCQkCiQkXGxhbWJkYSA9IGByIG1vZGVsJGJlc3RUdW5lJGxhbWJkYWAkJAoKYW5kIHRoZSBlcXVhdGlvbiBpcyAKCiQkdmlvbGVudGNyaW1lcy5wZXJwb3AgPSBgciB0aWR5X2NhZmxfMlsxLCAzXWAgKyAKYHIgdGlkeV9jYWZsXzJbMiwgM11gYHIgdGlkeV9jYWZsXzJbMiwgMV1gICsKYHIgdGlkeV9jYWZsXzJbMywgM11gYHIgdGlkeV9jYWZsXzJbMywgMV1gICsKYHIgdGlkeV9jYWZsXzJbNCwgM11gYHIgdGlkeV9jYWZsXzJbNCwgMV1gICsgXFwKYHIgdGlkeV9jYWZsXzJbNSwgM11gYHIgdGlkeV9jYWZsXzJbNSwgMV1gICsKYHIgdGlkeV9jYWZsXzJbNiwgM11gYHIgdGlkeV9jYWZsXzJbNiwgMV1gICsKYHIgdGlkeV9jYWZsXzJbNywgM11gYHIgdGlkeV9jYWZsXzJbNywgMV1gICsgXFwKYHIgdGlkeV9jYWZsXzJbOCwgM11gYHIgdGlkeV9jYWZsXzJbOCwgMV1gICsKYHIgdGlkeV9jYWZsXzJbOSwgM11gYHIgdGlkeV9jYWZsXzJbOSwgMV1gICsKYHIgdGlkeV9jYWZsXzJbMTAsIDNdYGByIHRpZHlfY2FmbF8yWzEwLCAxXWAgKyBcXApgciB0aWR5X2NhZmxfMlsxMSwgM11gYHIgdGlkeV9jYWZsXzJbMTEsIDFdYCArCmByIHRpZHlfY2FmbF8yWzEyLCAzXWBgciB0aWR5X2NhZmxfMlsxMiwgMV1gICsKYHIgdGlkeV9jYWZsXzJbMTMsIDNdYGByIHRpZHlfY2FmbF8yWzEzLCAxXWAgKyBcXApgciB0aWR5X2NhZmxfMlsxNCwgM11gYHIgdGlkeV9jYWZsXzJbMTQsIDFdYCArCmByIHRpZHlfY2FmbF8yWzE1LCAzXWBgciB0aWR5X2NhZmxfMlsxNSwgMV1gICsKYHIgdGlkeV9jYWZsXzJbMTYsIDNdYGByIHRpZHlfY2FmbF8yWzE2LCAxXWAkJAoKVGhlIHByZWRpY3Rpb24gZXJyb3Igb2YgdGhpcyBtb2RlbCBpcyAqKmByIHByZXR0eU51bShtaW5pbWl6ZWQkTVNFLCBiaWcubWFyayA9ICcsJylgKiouIAoKV2UgdGhlbiB1c2UgdGhlc2UgcHJlZGljdG9ycyBpbiBPTFMgYW5kIGZpbmQgdGhlIHByZWRpY3Rpb24gZXJyb3IgaXMgKipgciBzZXQuc2VlZCg0Mik7IHByZXR0eU51bShjdi5nbG1uZXQoeF9tYXRyaXhfZmxjYTIsIHlfdmlvbGVudF9jcmltZXMsIGxhbWJkYSA9IGMoMCwgMSkpJGN2bVsxXSwgYmlnLm1hcmsgPSAnLCcpYCoqLgoKYGBge3IgcmVzdWx0cyA9ICdhc2lzJ30KZml0X2NhZmxfNiA8LSBsbShhcy5mb3JtdWxhKHBhc3RlMCgidmlvbGVudGNyaW1lcy5wZXJwb3AgfiAiLCBwYXN0ZTAocHJlZGljdG9ycyhtb2RlbCksIGNvbGxhcHNlID0gIiArICIpKSksIAogICAgICAgICAgICAgICAgIGRhdGEgPSBkYXRhX2NhZmwpCgp0aWR5X2NhZmxfMyA8LSAKICAgIHRpZHkoZml0X2NhZmxfNikgJT4lIAogICAgbXV0YXRlKGlzSW50ZXJjZXB0ID0gaWZlbHNlKHRlcm0gPT0gIihJbnRlcmNlcHQpIiwgMCwgMSkpICU+JSAKICAgIGFycmFuZ2UoaXNJbnRlcmNlcHQsIHAudmFsdWUpICU+JQogICAgc2VsZWN0KC1pc0ludGVyY2VwdCkKCnRpZHlfY2FmbF8zICU+JSBwYW5kZXIoKQpgYGAKCldlIHNlZSB0aGVyZSBhcmUgbm93IHByZWRpY2F0b3JzIHRoYXQgYXJlIG5vdCBzaWduaWZpY2FudCBhdCB0aGUgMC4wNSBzaWduaWZpY2FuY2UgbGV2ZWwuCgokJHZpb2xlbnRjcmltZXMucGVycG9wID0gYHIgdGlkeV9jYWZsXzNbMSwgMl1gICsgCmByIHRpZHlfY2FmbF8zWzIsIDJdYGByIHRpZHlfY2FmbF8zWzIsIDFdYCArCmByIHRpZHlfY2FmbF8zWzMsIDJdYGByIHRpZHlfY2FmbF8zWzMsIDFdYCArCmByIHRpZHlfY2FmbF8zWzQsIDJdYGByIHRpZHlfY2FmbF8zWzQsIDFdYCArIFxcCmByIHRpZHlfY2FmbF8zWzUsIDJdYGByIHRpZHlfY2FmbF8zWzUsIDFdYCArCmByIHRpZHlfY2FmbF8zWzYsIDJdYGByIHRpZHlfY2FmbF8zWzYsIDFdYCArCmByIHRpZHlfY2FmbF8zWzcsIDJdYGByIHRpZHlfY2FmbF8zWzcsIDFdYCArIFxcCmByIHRpZHlfY2FmbF8zWzgsIDJdYGByIHRpZHlfY2FmbF8zWzgsIDFdYCArCmByIHRpZHlfY2FmbF8zWzksIDJdYGByIHRpZHlfY2FmbF8zWzksIDFdYCArCmByIHRpZHlfY2FmbF8zWzEwLCAyXWBgciB0aWR5X2NhZmxfM1sxMCwgMV1gICsgXFwKYHIgdGlkeV9jYWZsXzNbMTEsIDJdYGByIHRpZHlfY2FmbF8zWzExLCAxXWAgKwpgciB0aWR5X2NhZmxfM1sxMiwgMl1gYHIgdGlkeV9jYWZsXzNbMTIsIDFdYCArCmByIHRpZHlfY2FmbF8zWzEzLCAyXWBgciB0aWR5X2NhZmxfM1sxMywgMV1gICsgXFwKYHIgdGlkeV9jYWZsXzNbMTQsIDJdYGByIHRpZHlfY2FmbF8zWzE0LCAxXWAgKwpgciB0aWR5X2NhZmxfM1sxNSwgMl1gYHIgdGlkeV9jYWZsXzNbMTUsIDFdYCArCmByIHRpZHlfY2FmbF8zWzE2LCAyXWBgciB0aWR5X2NhZmxfM1sxNiwgMV1gJCQKCgpGb3IgZXhhbXBsZSwgaG9sZGluZyBhbGwgb3RoZXIgdmFyaWFibGVzIGNvbnN0YW50IGluIGEgY29tbXVuaXR5LAoKKyBBbiBpbmNyZWFzZSBpbiAxJSBvZiAqKmJsYWNrIHJlc2lkZW50cyoqLCBpbmNyZWFzZXMgdGhlIG51bWJlciBvZiB2aW9sZW50IGNyaW1lcyBwZXIgcGVyc29uIGJ5ICoqYHIgdGlkeV9jYWZsXzNbMiwgMl1gKiouCisgQW4gaW5jcmVhc2UgaW4gMSUgb2YgKiptYWxlcyB0aGF0IHRoYXQgYXJlIGRpdm9yY2VkKiosIGluY3JlYXNlcyB0aGUgbnVtYmVyIG9mIHZpb2xlbnQgY3JpbWVzIHBlciBwZXJzb24gYnkgKipgciB0aWR5X2NhZmxfM1szLCAyXWAqKi4KKyBBbiBpbmNyZWFzZSBpbiAxJSBvZiAqKkFzaWFuIHJlc2lkZW5jZXMqKiwgaW5jcmVhc2VzIHRoZSBudW1iZXIgb2YgdmlvbGVudCBjcmltZXMgcGVyIHBlcnNvbiBieSAqKmByIHRpZHlfY2FmbF8zWzMsIDJdYCoqLgorIEFuIGluY3JlYXNlIGluIDElIG9mICoqZmFtaWxpZXMgd2l0aCBraWRzIGFuZCAyIHBhcmVudHMqKiwgZGVjcmVhc2VzIHRoZSBudW1iZXIgb2YgdmlvbGVudCBjcmltZXMgcGVyIHBlcnNvbiBieSAqKmByIHRpZHlfY2FmbF8zWzQsIDJdYCoqLgorIEFuIGluY3JlYXNlIGluIDElIG9mICoqRW5nbGlzaCBvbmx5IHNwZWFrZXJzKiosIGRlY3JlYXNlcyB0aGUgbnVtYmVyIG9mIHZpb2xlbnQgY3JpbWVzIHBlciBwZXJzb24gYnkgKipgciB0aWR5X2NhZmxfM1s1LCAyXWAqKi4KKyBBbiBpbmNyZWFzZSBpbiAxJSBvZiAqKndvcmtpbmcgbW90aGVycyoqLCBkZWNyZWFzZXMgdGhlIG51bWJlciBvZiB2aW9sZW50IGNyaW1lcyBwZXIgcGVyc29uIGJ5ICoqYHIgdGlkeV9jYWZsXzNbNiwgMl1gKiouCisgQW4gaW5jcmVhc2UgaW4gMSUgb2YgKipvY2N1cGllZCBob3VzZXMqKiwgZGVjcmVhc2VzIHRoZSBudW1iZXIgb2YgdmlvbGVudCBjcmltZXMgcGVyIHBlcnNvbiBieSAqKmByIHRpZHlfY2FmbF8zWzcsIDJdYCoqLgoKVGhpcyBpcyBvbmx5IHRoZSBmaXJzdCBzZXZlbiB2YXJpYWJsZXMsIGJ1dCBzdWNoIHN0YXRlbWVudHMgY291bGQgYmUgYXBwbGllZCB0byBhbGwgcHJlZGljdG9ycy4KClRoZSBlcXVhdGlvbiBmcm9tIEVsYXN0aWNOZXQgYW5kIE9MUyBhcmUgc2ltaWxhciBpbiB0aGUgcmVzcGVjdCB0aGF0IHRoZXkgY29udGFpbiB0aGUgc2FtZSBwcmVkaWN0b3JzICh0aGlzIGlzIGJ5IGRlc2lnbiksIGJ1dCB0aGUgY29lZmZpY2llbnQgZXN0aW1hdGVzIGFyZSBzbGlnaHRseSBkaWZmZXJlbnQuIAoKCgoK